From bdd11f741b50daace3d49398f69247b11c1204bc Mon Sep 17 00:00:00 2001 From: Asher Date: Fri, 18 Oct 2019 18:20:02 -0500 Subject: [PATCH] Update to 1.39.2 Also too the opportunity to rewrite the build script since there was a change in the build steps (mainly how the product JSON is inserted) and to get the build changes out of the patch. It also no longer relies on external caching (we'll want to do this within CI instead). --- .gitignore | 1 + .travis.yml | 2 +- package.json | 26 +- scripts/build-json.js | 58 -- scripts/build.ts | 396 +++++++++++ scripts/ci.bash | 15 +- scripts/nbin-shim.js | 16 - scripts/nbin.js | 23 - scripts/optimize.js | 71 ++ scripts/product.json | 4 +- scripts/tasks.bash | 276 -------- scripts/tsconfig.json | 17 + scripts/vscode.patch | 1085 ++++++++---------------------- src/browser/api.ts | 2 +- src/browser/client.ts | 6 +- src/browser/upload.ts | 8 +- src/browser/workbench-build.html | 109 +++ src/browser/workbench.html | 70 ++ src/node/channel.ts | 7 +- src/node/cli.ts | 53 +- src/node/marketplace.ts | 2 +- src/node/nls.ts | 8 +- src/node/server.ts | 84 ++- src/node/update.ts | 28 +- yarn.lock | 75 ++- 25 files changed, 1122 insertions(+), 1320 deletions(-) delete mode 100644 scripts/build-json.js create mode 100644 scripts/build.ts delete mode 100644 scripts/nbin-shim.js delete mode 100644 scripts/nbin.js create mode 100644 scripts/optimize.js delete mode 100755 scripts/tasks.bash create mode 100644 scripts/tsconfig.json create mode 100644 src/browser/workbench-build.html create mode 100644 src/browser/workbench.html diff --git a/.gitignore b/.gitignore index 92c07daf..a2fff642 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ node_modules build release +binaries diff --git a/.travis.yml b/.travis.yml index 8b9b003f..ee09b940 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,7 @@ services: before_install: - export MAJOR_VERSION="2" - - export VSCODE_VERSION="1.38.1" + - export VSCODE_VERSION="1.39.2" - export VERSION="$MAJOR_VERSION.$TRAVIS_BUILD_NUMBER" - export TAG="$VERSION-vsc$VSCODE_VERSION" - if [[ "$TRAVIS_BRANCH" == "master" ]]; then export MINIFY="true"; fi diff --git a/package.json b/package.json index 0bc729b6..97b0ba1b 100644 --- a/package.json +++ b/package.json @@ -1,25 +1,27 @@ { "license": "MIT", "scripts": { - "ensure-in-vscode": "bash ./scripts/tasks.bash ensure-in-vscode", - "preinstall": "yarn ensure-in-vscode && cd ../../../ && yarn || true", + "runner": "cd ./scripts && node --max-old-space-size=32384 -r ts-node/register ./build.ts", + "preinstall": "yarn runner ensure-in-vscode && cd ../../../ && yarn || true", "postinstall": "rm -rf node_modules/@types/node", - "start": "yarn ensure-in-vscode && nodemon --watch ../../../out --verbose ../../../out/vs/server/main.js", - "watch": "yarn ensure-in-vscode && cd ../../../ && yarn watch", - "build": "bash ./scripts/tasks.bash build", - "package": "bash ./scripts/tasks.bash package", - "package-prebuilt": "bash ./scripts/tasks.bash package-prebuilt", - "binary": "bash ./scripts/tasks.bash binary", - "patch:generate": "yarn ensure-in-vscode && cd ../../../ && git diff --staged > ./src/vs/server/scripts/vscode.patch", - "patch:apply": "yarn ensure-in-vscode && cd ../../../ && git apply ./src/vs/server/scripts/vscode.patch" + "start": "yarn runner ensure-in-vscode && nodemon --watch ../../../out --verbose ../../../out/vs/server/main.js", + "watch": "yarn runner ensure-in-vscode && cd ../../../ && yarn watch", + "build": "yarn runner build", + "package": "yarn runner package", + "binary": "yarn runner binary", + "patch:generate": "yarn runner ensure-in-vscode && cd ../../../ && git diff --staged > ./src/vs/server/scripts/vscode.patch", + "patch:apply": "yarn runner ensure-in-vscode && cd ../../../ && git apply ./src/vs/server/scripts/vscode.patch" }, "devDependencies": { "@coder/nbin": "^1.2.2", + "@types/fs-extra": "^8.0.1", "@types/pem": "^1.9.5", "@types/safe-compare": "^1.1.0", "@types/tar-fs": "^1.16.1", "@types/tar-stream": "^1.6.1", - "nodemon": "^1.19.1" + "fs-extra": "^8.1.0", + "nodemon": "^1.19.1", + "ts-node": "^8.4.1" }, "resolutions": { "@types/node": "^10.12.12", @@ -27,7 +29,7 @@ }, "dependencies": { "@coder/logger": "^1.1.8", - "@coder/node-browser": "^1.0.5", + "@coder/node-browser": "^1.0.6", "@coder/requirefs": "^1.0.6", "httpolyglot": "^0.1.2", "pem": "^1.14.2", diff --git a/scripts/build-json.js b/scripts/build-json.js deleted file mode 100644 index 0f578ca7..00000000 --- a/scripts/build-json.js +++ /dev/null @@ -1,58 +0,0 @@ -// This builds the package and product JSON files for the final build. -const crypto = require("crypto"); -const fs = require("fs"); -const path = require("path"); -const rootPath = path.resolve(__dirname, ".."); -const sourcePath = process.argv[2]; -const buildPath = process.argv[3]; -const vscodeVersion = process.argv[4]; -const codeServerVersion = process.argv[5]; -const util = require(path.join(sourcePath, "build/lib/util")); - -function computeChecksum(filename) { - return crypto.createHash("md5").update(fs.readFileSync(filename)) - .digest("base64").replace(/=+$/, ""); -} - -const computeChecksums = (filenames) => { - const result = {}; - filenames.forEach(function (filename) { - result[filename] = computeChecksum(path.join(buildPath, "out", filename)); - }); - return result; -}; - -const mergeAndWrite = (name, json = {}) => { - const aJson = JSON.parse(fs.readFileSync(path.join(sourcePath, `${name}.json`))); - const bJson = JSON.parse(fs.readFileSync(path.join(rootPath, "scripts", `${name}.json`))); - - delete aJson.scripts; - delete aJson.dependencies; - delete aJson.devDependencies; - delete aJson.optionalDependencies; - - fs.writeFileSync(path.join(buildPath, `${name}.json`), JSON.stringify({ - ...aJson, - ...bJson, - ...json, - }, null, 2)); -}; - - -const writeProduct = () => { - const checksums = computeChecksums([ - "vs/workbench/workbench.web.api.js", - "vs/workbench/workbench.web.api.css", - "vs/code/browser/workbench/workbench.html", - "vs/code/browser/workbench/workbench.js", - "vs/server/src/node/cli.js", - "vs/server/src/node/uriTransformer.js", - "vs/server/src/login/index.html" - ]); - const date = new Date().toISOString(); - const commit = util.getVersion(rootPath); - mergeAndWrite("product", { commit, date, checksums }); - mergeAndWrite("package", { codeServerVersion: `${codeServerVersion}-vsc${vscodeVersion}` }); -}; - -writeProduct(); diff --git a/scripts/build.ts b/scripts/build.ts new file mode 100644 index 00000000..7c7446fe --- /dev/null +++ b/scripts/build.ts @@ -0,0 +1,396 @@ +import { Binary } from "@coder/nbin"; +import * as cp from "child_process"; +// import * as crypto from "crypto"; +import * as fs from "fs-extra"; +import * as os from "os"; +import * as path from "path"; +import * as util from "util"; + +enum Task { + /** + * Use before running anything that only works inside VS Code. + */ + EnsureInVscode = "ensure-in-vscode", + Binary = "binary", + Package = "package", + Build = "build", +} + +class Builder { + private readonly rootPath = path.resolve(__dirname, ".."); + private readonly outPath = process.env.OUT || this.rootPath; + private _target?: "darwin" | "alpine" | "linux"; + private task?: Task; + + public run(task: Task | undefined, args: string[]): void { + this.task = task; + this.doRun(task, args).catch((error) => { + console.error(error.message); + process.exit(1); + }); + } + + /** + * Writes to stdout with an optional newline. + */ + private log(message: string, skipNewline: boolean = false): void { + process.stdout.write(`[${this.task || "default"}] ${message}`); + if (!skipNewline) { + process.stdout.write("\n"); + } + } + + private async doRun(task: Task | undefined, args: string[]): Promise { + if (!task) { + throw new Error("No task provided"); + } + + if (task === Task.EnsureInVscode) { + return process.exit(this.isInVscode(this.rootPath) ? 0 : 1); + } + + // If we're inside VS Code assume we want to develop. In that case we should + // set an OUT directory and not build in this directory, otherwise when you + // build/watch VS Code the build directory will be included. + if (this.isInVscode(this.outPath)) { + throw new Error("Should not build inside VS Code; set the OUT environment variable"); + } + + this.ensureArgument("rootPath", this.rootPath); + this.ensureArgument("outPath", this.outPath); + + const arch = this.ensureArgument("arch", os.arch().replace(/^x/, "x86_")); + const target = this.ensureArgument("target", await this.target()); + const vscodeVersion = this.ensureArgument("vscodeVersion", args[0]); + const codeServerVersion = this.ensureArgument("codeServerVersion", args[1]); + + const stagingPath = path.join(this.outPath, "build"); + const vscodeSourcePath = path.join(stagingPath, `vscode-${vscodeVersion}-source`); + const binariesPath = path.join(this.outPath, "binaries"); + const binaryName = `code-server${codeServerVersion}-vsc${vscodeVersion}-${target}-${arch}`; + const finalBuildPath = path.join(stagingPath, `${binaryName}-built`); + + switch (task) { + case Task.Binary: + return this.binary(finalBuildPath, binariesPath, binaryName); + case Task.Package: + return this.package(vscodeSourcePath, binariesPath, binaryName); + case Task.Build: + return this.build(vscodeSourcePath, vscodeVersion, codeServerVersion, finalBuildPath); + default: + throw new Error(`No task matching "${task}"`); + } + } + + /** + * Get the target of the system. + */ + private async target(): Promise<"darwin" | "alpine" | "linux"> { + if (!this._target) { + if (process.env.OSTYPE && /^darwin/.test(process.env.OSTYPE)) { + this._target = "darwin"; + } else { + // Alpine's ldd doesn't have a version flag but if you use an invalid flag + // (like --version) it outputs the version to stderr and exits with 1. + const result = await util.promisify(cp.exec)("ldd --version") + .catch((error) => ({ stderr: error.message, stdout: "" })); + if (/^musl/.test(result.stderr) || /^musl/.test(result.stdout)) { + this._target = "alpine"; + } else { + this._target = "linux"; + } + } + } + return this._target; + } + + /** + * Make sure the argument is set. Display the value if it is. + */ + private ensureArgument(name: string, arg?: string): string { + if (!arg) { + this.log(`${name} is missing`); + throw new Error("Usage: "); + } + this.log(`${name} is "${arg}"`); + return arg; + } + + /** + * Return true if it looks like we're inside VS Code. This is used to prevent + * accidentally building inside while developing or to prevent trying to run + * `yarn` in VS Code when we aren't in VS Code. + */ + private isInVscode(pathToCheck: string): boolean { + let inside = false; + const maybeVsCode = path.join(pathToCheck, "../../../"); + try { + // If it has a package.json with the right name it's probably VS Code. + inside = require(path.join(maybeVsCode, "package.json")).name === "code-oss-dev"; + } catch (error) {} + this.log( + inside + ? `Running inside VS Code ([${maybeVsCode}]${path.relative(maybeVsCode, pathToCheck)})` + : "Not running inside VS Code" + ); + return inside; + } + + /** + * Build code-server within VS Code. + */ + private async build(vscodeSourcePath: string, vscodeVersion: string, codeServerVersion: string, finalBuildPath: string): Promise { + const task = async (message: string, fn: () => Promise): Promise => { + const time = Date.now(); + this.log(`${message}...`, true); + try { + const t = await fn(); + process.stdout.write(`took ${Date.now() - time}ms\n`); + return t; + } catch (error) { + process.stdout.write("failed\n"); + throw error; + } + }; + + // Install dependencies (should be cached by CI). + // Ignore scripts since we'll install VS Code dependencies separately. + await task("Installing code-server dependencies", async () => { + await util.promisify(cp.exec)("yarn --ignore-scripts", { cwd: this.rootPath }); + await util.promisify(cp.exec)("yarn postinstall", { cwd: this.rootPath }); + }); + + // Download and prepare VS Code if necessary (should be cached by CI). + const exists = fs.existsSync(vscodeSourcePath); + if (exists) { + this.log("Using existing VS Code directory"); + } else { + await task("Cloning VS Code", () => { + return util.promisify(cp.exec)( + "git clone https://github.com/microsoft/vscode" + + ` --quiet --branch "${vscodeVersion}"` + + ` --single-branch --depth=1 "${vscodeSourcePath}"`); + }); + + await task("Installing VS Code dependencies", () => { + return util.promisify(cp.exec)("yarn", { cwd: vscodeSourcePath }); + }); + + await task("Building default extensions", () => { + return util.promisify(cp.exec)( + "yarn gulp compile-extensions-build --max-old-space-size=32384", + { cwd: vscodeSourcePath }, + ); + }); + } + + // Clean before patching or it could fail if already patched. + await task("Patching VS Code", async () => { + await util.promisify(cp.exec)("git reset --hard", { cwd: vscodeSourcePath }); + await util.promisify(cp.exec)("git clean -fd", { cwd: vscodeSourcePath }); + await util.promisify(cp.exec)(`git apply ${this.rootPath}/scripts/vscode.patch`, { cwd: vscodeSourcePath }); + }); + + const serverPath = path.join(vscodeSourcePath, "src/vs/server"); + await task("Copying code-server into VS Code", async () => { + await fs.remove(serverPath); + await fs.mkdirp(serverPath); + await Promise.all(["main.js", "node_modules", "src", "typings"].map((fileName) => { + return fs.copy(path.join(this.rootPath, fileName), path.join(serverPath, fileName)); + })); + }); + + await task("Building VS Code", () => { + return util.promisify(cp.exec)("yarn gulp compile-build --max-old-space-size=32384", { cwd: vscodeSourcePath }); + }); + + await task("Optimizing VS Code", async () => { + await fs.copyFile(path.join(this.rootPath, "scripts/optimize.js"), path.join(vscodeSourcePath, "coder.js")); + await util.promisify(cp.exec)(`yarn gulp optimize --max-old-space-size=32384 --gulpfile ./coder.js`, { cwd: vscodeSourcePath }); + }); + + const { productJson, packageJson } = await task("Generating final package.json and product.json", async () => { + const merge = async (name: string, extraJson: { [key: string]: string } = {}): Promise<{ [key: string]: string }> => { + const [aJson, bJson] = (await Promise.all([ + fs.readFile(path.join(vscodeSourcePath, `${name}.json`), "utf8"), + fs.readFile(path.join(this.rootPath, `scripts/${name}.json`), "utf8"), + ])).map((raw) => { + const json = JSON.parse(raw); + delete json.scripts; + delete json.dependencies; + delete json.devDependencies; + delete json.optionalDependencies; + return json; + }); + + return { ...aJson, ...bJson, ...extraJson }; + }; + + const date = new Date().toISOString(); + const commit = require(path.join(vscodeSourcePath, "build/lib/util")).getVersion(this.rootPath); + + const [productJson, packageJson] = await Promise.all([ + merge("product", { commit, date }), + merge("package", { codeServerVersion: `${codeServerVersion}-vsc${vscodeVersion}` }), + ]); + + // We could do this before the optimization but then it'd be copied into + // three files and unused in two which seems like a waste of bytes. + const apiPath = path.join(vscodeSourcePath, "out-vscode/vs/workbench/workbench.web.api.js"); + await fs.writeFile(apiPath, (await fs.readFile(apiPath, "utf8")).replace('{ /*BUILD->INSERT_PRODUCT_CONFIGURATION*/}', JSON.stringify({ + version: packageJson.version, + codeServerVersion: packageJson.codeServerVersion, + ...productJson, + }))); + + return { productJson, packageJson }; + }); + + if (process.env.MINIFY) { + await task("Minifying VS Code", () => { + return util.promisify(cp.exec)("yarn gulp minify --max-old-space-size=32384 --gulpfile ./coder.js", { cwd: vscodeSourcePath }); + }); + } + + const finalServerPath = path.join(finalBuildPath, "out/vs/server"); + await task("Copying into final build directory", async () => { + await fs.remove(finalBuildPath); + await fs.mkdirp(finalBuildPath); + await Promise.all([ + fs.copy(path.join(vscodeSourcePath, "remote/node_modules"), path.join(finalBuildPath, "node_modules")), + fs.copy(path.join(vscodeSourcePath, ".build/extensions"), path.join(finalBuildPath, "extensions")), + fs.copy(path.join(vscodeSourcePath, `out-vscode${process.env.MINIFY ? "-min" : ""}`), path.join(finalBuildPath, "out")).then(() => { + return Promise.all([ + fs.remove(path.join(finalServerPath, "node_modules")).then(() => { + return fs.copy(path.join(serverPath, "node_modules"), path.join(finalServerPath, "node_modules")); + }), + fs.copy(path.join(serverPath, "src/browser/workbench-build.html"), path.join(finalServerPath, "src/browser/workbench.html")), + ]); + }), + ]); + }); + + if (process.env.MINIFY) { + await task("Restricting to production dependencies", async () => { + await Promise.all(["package.json", "yarn.lock"].map((fileName) => { + Promise.all([ + fs.copy(path.join(this.rootPath, fileName), path.join(finalServerPath, fileName)), + fs.copy(path.join(path.join(vscodeSourcePath, "remote"), fileName), path.join(finalBuildPath, fileName)), + ]); + })); + + await Promise.all([ + util.promisify(cp.exec)("yarn --production --ignore-scripts", { cwd: finalServerPath }), + util.promisify(cp.exec)("yarn --production", { cwd: finalBuildPath }), + ]); + + await Promise.all(["package.json", "yarn.lock"].map((fileName) => { + return Promise.all([ + fs.remove(path.join(finalServerPath, fileName)), + fs.remove(path.join(finalBuildPath, fileName)), + ]); + })); + }); + } + + await task("Writing final package.json and product.json", () => { + return Promise.all([ + fs.writeFile(path.join(finalBuildPath, "package.json"), JSON.stringify(packageJson, null, 2)), + fs.writeFile(path.join(finalBuildPath, "product.json"), JSON.stringify(productJson, null, 2)), + ]); + }); + + // This is so it doesn't get cached along with VS Code (no point). + await task("Removing copied server", () => fs.remove(serverPath)); + + // Prepend code to the target which enables finding files within the binary. + const prependLoader = async (relativeFilePath: string): Promise => { + const filePath = path.join(finalBuildPath, relativeFilePath); + const shim = ` + if (!global.NBIN_LOADED) { + try { + const nbin = require("nbin"); + nbin.shimNativeFs("${finalBuildPath}"); + global.NBIN_LOADED = true; + const path = require("path"); + const rg = require("vscode-ripgrep"); + rg.binaryRgPath = rg.rgPath; + rg.rgPath = path.join(require("os").tmpdir(), "code-server", path.basename(rg.binaryRgPath)); + } catch (error) { /* Not in the binary. */ } + } + `; + await fs.writeFile(filePath, shim + (await fs.readFile(filePath, "utf8"))); + }; + + await task("Prepending nbin loader", () => { + return Promise.all([ + prependLoader("out/vs/server/main.js"), + prependLoader("out/bootstrap-fork.js"), + prependLoader("extensions/node_modules/typescript/lib/tsserver.js"), + ]); + }); + + // TODO: fix onigasm dep + // # onigasm 2.2.2 has a bug that makes it broken for PHP files so use 2.2.1. + // # https://github.com/NeekSandhu/onigasm/issues/17 + // function fix-onigasm() { + // local onigasmPath="${buildPath}/node_modules/onigasm-umd" + // rm -rf "${onigasmPath}" + // git clone "https://github.com/alexandrudima/onigasm-umd" "${onigasmPath}" + // cd "${onigasmPath}" && yarn && yarn add --dev onigasm@2.2.1 && yarn package + // mkdir "${onigasmPath}-temp" + // mv "${onigasmPath}/"{release,LICENSE} "${onigasmPath}-temp" + // rm -rf "${onigasmPath}" + // mv "${onigasmPath}-temp" "${onigasmPath}" + // } + + this.log(`Final build: ${finalBuildPath}`); + } + + /** + * Bundles the built code into a binary. + */ + private async binary(targetPath: string, binariesPath: string, binaryName: string): Promise { + const bin = new Binary({ + mainFile: path.join(targetPath, "out/vs/server/main.js"), + target: await this.target(), + }); + + bin.writeFiles(path.join(targetPath, "**")); + + await fs.mkdirp(binariesPath); + + const binaryPath = path.join(binariesPath, binaryName); + await fs.writeFile(binaryPath, await bin.build()); + await fs.chmod(binaryPath, "755"); + + this.log(`Binary: ${binaryPath}`); + } + + /** + * Package the binary into a release archive. + */ + private async package(vscodeSourcePath: string, binariesPath: string, binaryName: string): Promise { + const releasePath = path.join(this.outPath, "release"); + const archivePath = path.join(releasePath, binaryName); + + await fs.remove(archivePath); + await fs.mkdirp(archivePath); + + await fs.copyFile(path.join(binariesPath, binaryName), path.join(archivePath, "code-server")); + await fs.copyFile(path.join(this.rootPath, "README.md"), path.join(archivePath, "README.md")); + await fs.copyFile(path.join(vscodeSourcePath, "LICENSE.txt"), path.join(archivePath, "LICENSE.txt")); + await fs.copyFile(path.join(vscodeSourcePath, "ThirdPartyNotices.txt"), path.join(archivePath, "ThirdPartyNotices.txt")); + + if ((await this.target()) === "darwin") { + await util.promisify(cp.exec)(`zip -r "${binaryName}.zip" "${binaryName}"`, { cwd: releasePath }); + this.log(`Archive: ${archivePath}.zip`); + } else { + await util.promisify(cp.exec)(`tar -czf "${binaryName}.tar.gz" "${binaryName}"`, { cwd: releasePath }); + this.log(`Archive: ${archivePath}.tar.gz`); + } + } +} + +const builder = new Builder(); +builder.run(process.argv[2] as Task, process.argv.slice(3)); diff --git a/scripts/ci.bash b/scripts/ci.bash index c5863b2f..96aff3ae 100755 --- a/scripts/ci.bash +++ b/scripts/ci.bash @@ -1,7 +1,6 @@ #!/bin/bash set -euo pipefail -# Build using a Docker container. function docker-build() { local target="${TARGET:-}" local image="codercom/nbin-${target}" @@ -12,15 +11,15 @@ function docker-build() { fi local containerId - containerId=$(docker create --network=host --rm -it -v "$(pwd)"/.cache:/src/.cache "${image}") + # Use a mount so we can cache the results. + containerId=$(docker create --network=host --rm -it -v "$(pwd)":/src "${image}") docker start "${containerId}" - docker exec "${containerId}" mkdir -p /src - # TODO: temporary as long as we are rebuilding modules. + # TODO: Might be better to move these dependencies to the images or create new + # ones on top of these. if [[ "${image}" == "codercom/nbin-alpine" ]] ; then docker exec "${containerId}" apk add libxkbfile-dev libsecret-dev else - # TODO: at some point git existed but it seems to have disappeared. docker exec "${containerId}" yum install -y libxkbfile-devel libsecret-devel git fi @@ -31,19 +30,15 @@ function docker-build() { bash -c "cd /src && CI=true GITHUB_TOKEN=${token} MINIFY=${minify} yarn ${command} ${args}" } - docker cp ./. "${containerId}":/src docker-exec build if [[ -n "${package}" ]] ; then docker-exec binary docker-exec package - mkdir -p release - docker cp "${containerId}":/src/release/. ./release/ fi - docker stop "${containerId}" + docker kill "${containerId}" } -# Build locally. function local-build() { function local-exec() { local command="${1}" ; shift diff --git a/scripts/nbin-shim.js b/scripts/nbin-shim.js deleted file mode 100644 index 8a8f8644..00000000 --- a/scripts/nbin-shim.js +++ /dev/null @@ -1,16 +0,0 @@ -// This file is prepended to loader/entry code (like our main.js or VS Code's -// bootstrap-fork.js). {{ROOT_PATH}} is replaced during the build process. -if (!global.NBIN_LOADED) { - try { - const nbin = require("nbin"); - nbin.shimNativeFs("{{ROOT_PATH}}"); - global.NBIN_LOADED = true; - const path = require("path"); - const rg = require("vscode-ripgrep"); - rg.binaryRgPath = rg.rgPath; - rg.rgPath = path.join( - require("os").tmpdir(), - `code-server/${path.basename(rg.binaryRgPath)}` - ); - } catch (error) { /* Not in the binary. */ } -} diff --git a/scripts/nbin.js b/scripts/nbin.js deleted file mode 100644 index 11926729..00000000 --- a/scripts/nbin.js +++ /dev/null @@ -1,23 +0,0 @@ -const { Binary } = require("@coder/nbin"); -const fs = require("fs"); -const path = require("path"); - -const source = process.argv[2]; -const target = process.argv[3]; -const binaryName = process.argv[4]; - -const bin = new Binary({ - mainFile: path.join(source, "out/vs/server/main.js"), - target: target, -}); - -bin.writeFiles(path.join(source, "**")); - -bin.build().then((binaryData) => { - const outputPath = path.join(source, binaryName); - fs.writeFileSync(outputPath, binaryData); - fs.chmodSync(outputPath, "755"); -}).catch((ex) => { - console.error(ex); - process.exit(1); -}); diff --git a/scripts/optimize.js b/scripts/optimize.js new file mode 100644 index 00000000..baf609dc --- /dev/null +++ b/scripts/optimize.js @@ -0,0 +1,71 @@ +// This must be ran from VS Code's root. +const gulp = require("gulp"); +const path = require("path"); +const _ = require("underscore"); +const buildfile = require("./src/buildfile"); +const common = require("./build/lib/optimize"); +const util = require("./build/lib/util"); +const deps = require("./build/dependencies"); + +const vscodeEntryPoints = _.flatten([ + buildfile.entrypoint("vs/workbench/workbench.web.api"), + buildfile.entrypoint("vs/server/src/node/cli"), + buildfile.base, + buildfile.workbenchWeb, + buildfile.workerExtensionHost, + buildfile.keyboardMaps, + buildfile.entrypoint('vs/platform/files/node/watcher/unix/watcherApp', ["vs/css", "vs/nls"]), + buildfile.entrypoint('vs/platform/files/node/watcher/nsfw/watcherApp', ["vs/css", "vs/nls"]), + buildfile.entrypoint('vs/workbench/services/extensions/node/extensionHostProcess', ["vs/css", "vs/nls"]), +]); + +const vscodeResources = [ + "out-build/vs/server/main.js", + "out-build/vs/server/src/node/uriTransformer.js", + "!out-build/vs/server/doc/**", + "out-build/vs/code/browser/workbench/**", + "out-build/vs/server/src/media/*", + "out-build/vs/workbench/services/extensions/worker/extensionHostWorkerMain.js", + "out-build/bootstrap.js", + "out-build/bootstrap-fork.js", + "out-build/bootstrap-amd.js", + "out-build/paths.js", + "out-build/vs/**/*.{svg,png}", + '!out-build/vs/code/electron-browser/**', + "out-build/vs/base/common/performance.js", + "out-build/vs/base/node/languagePacks.js", + "out-build/vs/base/browser/ui/octiconLabel/octicons/**", + "out-build/vs/base/browser/ui/codiconLabel/codicon/**", + "out-build/vs/workbench/browser/media/*-theme.css", + "out-build/vs/workbench/contrib/debug/**/*.json", + "out-build/vs/workbench/contrib/externalTerminal/**/*.scpt", + "out-build/vs/workbench/contrib/webview/browser/pre/*.js", + "out-build/vs/**/markdown.css", + "out-build/vs/workbench/contrib/tasks/**/*.json", + "out-build/vs/platform/files/**/*.md", + "!**/test/**" +]; + +const rootPath = __dirname; +const nodeModules = ["electron", "original-fs"] + .concat(_.uniq(deps.getProductionDependencies(rootPath).map((d) => d.name))) + .concat(_.uniq(deps.getProductionDependencies(path.join(rootPath, "src/vs/server")).map((d) => d.name))) + .concat(Object.keys(process.binding("natives")).filter((n) => !/^_|\//.test(n))); + +gulp.task("optimize", gulp.series( + util.rimraf("out-vscode"), + common.optimizeTask({ + src: "out-build", + entryPoints: vscodeEntryPoints, + resources: vscodeResources, + loaderConfig: common.loaderConfig(nodeModules), + out: "out-vscode", + inlineAmdImages: true, + bundleInfo: undefined + }), +)); + +gulp.task("minify", gulp.series( + util.rimraf("out-vscode-min"), + common.minifyTask("out-vscode") +)); diff --git a/scripts/product.json b/scripts/product.json index 4e864069..dabf03e8 100644 --- a/scripts/product.json +++ b/scripts/product.json @@ -15,5 +15,7 @@ "win32ShellNameShort": "C&ode Server", "darwinBundleIdentifier": "com.code.server", "linuxIconName": "com.code.server", - "urlProtocol": "code-server" + "urlProtocol": "code-server", + "updateUrl": "https://api.github.com/repos/cdr/code-server/releases", + "quality": "latest" } diff --git a/scripts/tasks.bash b/scripts/tasks.bash deleted file mode 100755 index e3a026fe..00000000 --- a/scripts/tasks.bash +++ /dev/null @@ -1,276 +0,0 @@ -#!/bin/bash -set -euox pipefail - -function log() { - local message="${1}" ; shift - local level="${1:-info}" - if [[ "${level}" == "error" ]] ; then - >&2 echo "${message}" - else - echo "${message}" - fi -} - -# Copy code-server into VS Code along with its dependencies. -function copy-server() { - local serverPath="${sourcePath}/src/vs/server" - rm -rf "${serverPath}" - mkdir -p "${serverPath}" - - cp -r "${rootPath}/src" "${serverPath}" - cp -r "${rootPath}/typings" "${serverPath}" - cp "${rootPath}/main.js" "${serverPath}" - cp "${rootPath}/package.json" "${serverPath}" - cp "${rootPath}/yarn.lock" "${serverPath}" - - if [[ -d "${rootPath}/node_modules" ]] ; then - cp -r "${rootPath}/node_modules" "${serverPath}" - else - # Ignore scripts to avoid also installing VS Code dependencies which has - # already been done. - cd "${serverPath}" && yarn --ignore-scripts - rm -r node_modules/@types/node # I keep getting type conflicts - fi - - # TODO: Duplicate identifier issue. There must be a better way to fix this. - if [[ "${target}" == "darwin" ]] ; then - rm "${serverPath}/node_modules/fsevents/node_modules/safe-buffer/index.d.ts" - fi -} - -# Prepend the nbin shim which enables finding files within the binary. -function prepend-loader() { - local filePath="${buildPath}/${1}" ; shift - cat "${rootPath}/scripts/nbin-shim.js" "${filePath}" > "${filePath}.temp" - mv "${filePath}.temp" "${filePath}" - # Using : as the delimiter so the escaping here is easier to read. - # ${parameter/pattern/string}, so the pattern is /: (if the pattern starts - # with / it matches all instances) and the string is \\: (results in \:). - if [[ "${target}" == "darwin" ]] ; then - sed -i "" -e "s:{{ROOT_PATH}}:${buildPath//:/\\:}:g" "${filePath}" - else - sed -i "s:{{ROOT_PATH}}:${buildPath//:/\\:}:g" "${filePath}" - fi -} - -# Copy code-server into VS Code then build it. -function build-code-server() { - copy-server - cd "${sourcePath}" && yarn gulp compile-build --max-old-space-size=32384 - - local min="" - if [[ -n "${minify}" ]] ; then - min="-min" - yarn gulp minify-vscode --max-old-space-size=32384 - else - yarn gulp optimize-vscode --max-old-space-size=32384 - fi - - rm -rf "${buildPath}" - mkdir -p "${buildPath}" - - # Rebuild to make sure native modules work on the target system. - cp "${sourcePath}/remote/"{package.json,yarn.lock,.yarnrc} "${buildPath}" - cd "${buildPath}" && yarn --production --force --build-from-source - rm "${buildPath}/"{package.json,yarn.lock,.yarnrc} - - cp -r "${sourcePath}/.build/extensions" "${buildPath}" - cp -r "${sourcePath}/out-vscode${min}" "${buildPath}/out" - node "${rootPath}/scripts/build-json.js" "${sourcePath}" "${buildPath}" "${vscodeVersion}" "${codeServerVersion}" - - # Only keep production dependencies for the server. - cp "${rootPath}/"{package.json,yarn.lock} "${buildPath}/out/vs/server" - cd "${buildPath}/out/vs/server" && yarn --production --ignore-scripts - rm "${buildPath}/out/vs/server/"{package.json,yarn.lock} - - # onigasm 2.2.2 has a bug that makes it broken for PHP files so use 2.2.1. - # https://github.com/NeekSandhu/onigasm/issues/17 - local onigasmPath="${buildPath}/node_modules/onigasm-umd" - rm -rf "${onigasmPath}" - git clone "https://github.com/alexandrudima/onigasm-umd" "${onigasmPath}" - cd "${onigasmPath}" && yarn && yarn add --dev onigasm@2.2.1 && yarn package - mkdir "${onigasmPath}-temp" - mv "${onigasmPath}/"{release,LICENSE} "${onigasmPath}-temp" - rm -rf "${onigasmPath}" - mv "${onigasmPath}-temp" "${onigasmPath}" - - prepend-loader "out/vs/server/main.js" - prepend-loader "out/bootstrap-fork.js" - prepend-loader "extensions/node_modules/typescript/lib/tsserver.js" - - log "Final build: ${buildPath}" -} - -# Download and extract a tar from a URL with either curl or wget depending on -# which is available. -function download-tar() { - local url="${1}" ; shift - if command -v wget &> /dev/null ; then - wget "${url}" --quiet -O - | tar -C "${stagingPath}" -xz - else - curl "${url}" --silent --fail | tar -C "${stagingPath}" -xz - fi -} - -# Download a pre-built package. If it doesn't exist and we are in the CI, exit. -# Otherwise the return will be whether it existed or not. The pre-built package -# is provided to reduce CI build time. -function download-pre-built() { - local archiveName="${1}" ; shift - local url="https://codesrv-ci.cdr.sh/${archiveName}" - if ! download-tar "${url}" ; then - if [[ -n "${ci}" ]] ; then - log "${url} does not exist" "error" - exit 1 - fi - return 1 - fi - return 0 -} - -# Fully build code-server. -function build-task() { - mkdir -p "${stagingPath}" - if [[ ! -d "${sourcePath}" ]] ; then - if ! download-pre-built "vscode-${vscodeVersion}.tar.gz" ; then - git clone https://github.com/microsoft/vscode --quiet \ - --branch "${vscodeVersion}" --single-branch --depth=1 \ - "${sourcePath}" - fi - fi - cd "${sourcePath}" - git reset --hard && git clean -fd - git apply "${rootPath}/scripts/vscode.patch" - if [[ ! -d "${sourcePath}/node_modules" ]] ; then - if [[ -n "${ci}" ]] ; then - log "Pre-built VS Code ${vscodeVersion} has no node_modules" "error" - exit 1 - fi - yarn - fi - if [[ ! -d "${sourcePath}/.build/extensions" ]] ; then - if [[ -n "${ci}" ]] ; then - log "Pre-built VS Code ${vscodeVersion} has no built extensions" "error" - exit 1 - fi - yarn gulp compile-extensions-build --max-old-space-size=32384 - fi - build-code-server -} - -# Package the binary into a tar or zip for release. -function package-task() { - local archivePath="${releasePath}/${binaryName}" - rm -rf "${archivePath}" - mkdir -p "${archivePath}" - - cp "${buildPath}/${binaryName}" "${archivePath}/code-server" - cp "${rootPath}/README.md" "${archivePath}" - cp "${sourcePath}/LICENSE.txt" "${archivePath}" - cp "${sourcePath}/ThirdPartyNotices.txt" "${archivePath}" - - cd "${releasePath}" - if [[ "${target}" == "darwin" ]] ; then - zip -r "${binaryName}.zip" "${binaryName}" - log "Archive: ${archivePath}.zip" - else - tar -czf "${binaryName}.tar.gz" "${binaryName}" - log "Archive: ${archivePath}.tar.gz" - fi -} - -# Bundle built code into a binary. -function binary-task() { - cd "${rootPath}" - node "${rootPath}/scripts/nbin.js" "${buildPath}" "${target}" "${binaryName}" - log "Binary: ${buildPath}/${binaryName}" -} - -# Check if it looks like we are inside VS Code. -function in-vscode () { - local dir="${1}" ; shift - local maybeVsCode - local dirName - maybeVsCode="$(cd "${dir}/../../.." ; pwd -P)" - dirName="$(basename "${maybeVsCode}")" - if [[ "${dirName}" != "vscode" ]] ; then - return 1 - fi - if [[ ! -f "${maybeVsCode}/package.json" ]] ; then - return 1 - fi - if ! grep '"name": "code-oss-dev"' "${maybeVsCode}/package.json" -q ; then - return 1 - fi - return 0 -} - -function main() { - local rootPath - rootPath="$(cd "$(dirname "${0}")/.." ; pwd -P)" - - local task="${1}" ; shift - if [[ "${task}" == "ensure-in-vscode" ]] ; then - if ! in-vscode "${rootPath}"; then - log "Not in VS Code" "error" - exit 1 - fi - exit 0 - fi - - # This lets you build in a separate directory since building within this - # directory while developing makes it hard to keep developing since compiling - # will compile everything in the build directory as well. - local outPath="${OUT:-${rootPath}}" - local releasePath="${outPath}/release" - local stagingPath="${outPath}/build" - - # If we're inside a VS Code directory, assume we want to develop. In that case - # we should set an OUT directory and not build in this directory. - if in-vscode "${outPath}" ; then - log "Set the OUT environment variable to something outside of VS Code" "error" - exit 1 - fi - - local vscodeVersion="${1}" ; shift - local sourceName="vscode-${vscodeVersion}-source" - local sourcePath="${stagingPath}/${sourceName}" - - if [[ "${task}" == "package-prebuilt" ]] ; then - local archiveName="vscode-${vscodeVersion}.tar.gz" - cd "${sourcePath}" - git reset --hard && git clean -xfd -e '.build/extensions' -e 'node_modules' - cd "${stagingPath}" - tar -czf "${archiveName}" "${sourceName}" - mkdir -p "${releasePath}" && mv -f "${archiveName}" "${releasePath}" - exit 0 - fi - - local codeServerVersion="${1}" ; shift - local ci="${CI:-}" - local minify="${MINIFY:-}" - - local arch - arch=$(uname -m) - - local target="linux" - local ostype="${OSTYPE:-}" - if [[ "${ostype}" == "darwin"* ]] ; then - target="darwin" - else - # On Alpine there seems no way to get the version except to use an invalid - # command which will output the version to stderr and exit with 1. - local output - output=$(ldd --version 2>&1 || :) - if [[ "${output}" == "musl"* ]] ; then - target="alpine" - fi - fi - - local binaryName="code-server${codeServerVersion}-vsc${vscodeVersion}-${target}-${arch}" - local buildPath="${stagingPath}/${binaryName}-built" - - "${task}-task" "$@" -} - -main "$@" diff --git a/scripts/tsconfig.json b/scripts/tsconfig.json new file mode 100644 index 00000000..149a7f36 --- /dev/null +++ b/scripts/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "module": "commonjs", + "moduleResolution": "node", + "noImplicitAny": true, + "experimentalDecorators": true, + "noImplicitReturns": true, + "noUnusedLocals": true, + "noImplicitThis": true, + "alwaysStrict": true, + "strictBindCallApply": true, + "strictNullChecks": true, + "forceConsistentCasingInFileNames": true, + "baseUrl": ".", + "target": "esnext" + } +} diff --git a/scripts/vscode.patch b/scripts/vscode.patch index 43c9c0da..be964624 100644 --- a/scripts/vscode.patch +++ b/scripts/vscode.patch @@ -1,102 +1,24 @@ -diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js -index 6bb695db68..7f6c5cd3cb 100644 ---- a/build/gulpfile.vscode.js -+++ b/build/gulpfile.vscode.js -@@ -47,24 +47,28 @@ const nodeModules = ['electron', 'original-fs'] - - // Build - const vscodeEntryPoints = _.flatten([ -- buildfile.entrypoint('vs/workbench/workbench.desktop.main'), -+ buildfile.entrypoint('vs/workbench/workbench.web.api'), -+ buildfile.entrypoint('vs/server/src/node/cli'), - buildfile.base, - buildfile.serviceWorker, -- buildfile.workbenchDesktop, -- buildfile.code -+ buildfile.workbenchWeb, -+ buildfile.workerExtensionHost, -+ buildfile.keyboardMaps, - ]); - - const vscodeResources = [ -- 'out-build/main.js', -- 'out-build/cli.js', -- 'out-build/driver.js', -+ 'out-build/vs/server/main.js', -+ 'out-build/vs/server/src/node/uriTransformer.js', -+ 'out-build/vs/code/browser/workbench/**', -+ 'out-build/vs/server/src/media/*', -+ 'out-build/vs/workbench/services/extensions/worker/extensionHostWorkerMain.js', -+ '!out-build/vs/server/doc/**', - 'out-build/bootstrap.js', - 'out-build/bootstrap-fork.js', - 'out-build/bootstrap-amd.js', - 'out-build/bootstrap-window.js', - 'out-build/paths.js', - 'out-build/vs/**/*.{svg,png,html}', -- '!out-build/vs/code/browser/**/*.html', - 'out-build/vs/base/common/performance.js', - 'out-build/vs/base/node/languagePacks.js', - 'out-build/vs/base/node/{stdForkStart.js,terminateProcess.sh,cpuUsage.sh,ps.sh}', -@@ -79,11 +83,7 @@ const vscodeResources = [ - 'out-build/vs/workbench/contrib/welcome/walkThrough/**/*.md', - 'out-build/vs/platform/files/**/*.exe', - 'out-build/vs/platform/files/**/*.md', -- 'out-build/vs/code/electron-browser/workbench/**', -- 'out-build/vs/code/electron-browser/sharedProcess/sharedProcess.js', -- 'out-build/vs/code/electron-browser/issue/issueReporter.js', -- 'out-build/vs/code/electron-browser/processExplorer/processExplorer.js', -- '!**/test/**' -+ '!**/test/**', - ]; - - const optimizeVSCodeTask = task.define('optimize-vscode', task.series( -@@ -627,4 +627,3 @@ function getSettingsSearchBuildId(packageJson) { - throw new Error('Could not determine build number: ' + e.toString()); - } - } -- -diff --git a/src/vs/base/browser/mouseEvent.ts b/src/vs/base/browser/mouseEvent.ts -index 4c7295e3b9..b0af2cdd62 100644 ---- a/src/vs/base/browser/mouseEvent.ts -+++ b/src/vs/base/browser/mouseEvent.ts -@@ -160,6 +160,8 @@ export class StandardWheelEvent { - this.deltaY = e1.wheelDeltaY / 120; - } else if (typeof e2.VERTICAL_AXIS !== 'undefined' && e2.axis === e2.VERTICAL_AXIS) { - this.deltaY = -e2.detail / 3; -+ } else if (browser.isFirefox) { -+ this.deltaY = -e.deltaY / 3; - } else { - this.deltaY = -e.deltaY / 40; - } -@@ -173,6 +175,8 @@ export class StandardWheelEvent { - } - } else if (typeof e2.HORIZONTAL_AXIS !== 'undefined' && e2.axis === e2.HORIZONTAL_AXIS) { - this.deltaX = -e.detail / 3; -+ } else if (browser.isFirefox) { -+ this.deltaX = -e.deltaX / 3; - } else { - this.deltaX = -e.deltaX / 40; - } diff --git a/src/vs/base/common/network.ts b/src/vs/base/common/network.ts -index 4f93e06df0..ae63e64a7f 100644 +index 6d41e85e42..f845d0bf9e 100644 --- a/src/vs/base/common/network.ts +++ b/src/vs/base/common/network.ts -@@ -48,7 +48,7 @@ export namespace Schemas { +@@ -48,7 +48,9 @@ export namespace Schemas { export const command: string = 'command'; - export const vscodeRemote: string = 'vscode-remote'; ++ // NOTE@coder: Changed this so it'll be reflected in the explorer to prevent ++ // confusion with vscode-remote itself. + export const vscodeRemote: string = 'code-server'; export const vscodeRemoteResource: string = 'vscode-remote-resource'; -@@ -82,13 +82,11 @@ class RemoteAuthoritiesImpl { - } - - public rewrite(authority: string, path: string): URI { -- const host = this._hosts[authority]; +@@ -96,12 +98,12 @@ class RemoteAuthoritiesImpl { + if (host && host.indexOf(':') !== -1) { + host = `[${host}]`; + } - const port = this._ports[authority]; ++ // NOTE@coder: Changed this to work against the current path. const connectionToken = this._connectionTokens[authority]; return URI.from({ scheme: platform.isWeb ? this._preferredWebSchema : Schemas.vscodeRemoteResource, @@ -104,23 +26,19 @@ index 4f93e06df0..ae63e64a7f 100644 - path: `/vscode-remote-resource`, + authority: window.location.host, + path: `${window.location.pathname.replace(/\/+$/, '')}/vscode-remote-resource`, - query: `path=${encodeURIComponent(path)}&tkn=${encodeURIComponent(connectionToken)}` + query: `path=${encodeURIComponent(uri.path)}&tkn=${encodeURIComponent(connectionToken)}` }); } diff --git a/src/vs/base/common/platform.ts b/src/vs/base/common/platform.ts -index 07759dffe5..9148d7c1f0 100644 +index a657f4a4d9..66bd13dffa 100644 --- a/src/vs/base/common/platform.ts +++ b/src/vs/base/common/platform.ts -@@ -54,8 +54,18 @@ if (typeof navigator === 'object' && !isElectronRenderer) { - _isMacintosh = _userAgent.indexOf('Macintosh') >= 0; - _isLinux = _userAgent.indexOf('Linux') >= 0; +@@ -56,6 +56,16 @@ if (typeof navigator === 'object' && !isElectronRenderer) { _isWeb = true; -- _locale = navigator.language; -- _language = _locale; -+ _locale = LANGUAGE_DEFAULT; -+ _language = LANGUAGE_DEFAULT; -+ const rawNlsConfig = typeof document !== 'undefined' -+ && document.getElementById('vscode-remote-nls-configuration')!.getAttribute('data-settings')!; + _locale = navigator.language; + _language = _locale; ++ const el = typeof document !== 'undefined' && document.getElementById('vscode-remote-nls-configuration'); ++ const rawNlsConfig = el && el.getAttribute('data-settings'); + if (rawNlsConfig) { + try { + const nlsConfig: NLSConfig = JSON.parse(rawNlsConfig); @@ -133,147 +51,73 @@ index 07759dffe5..9148d7c1f0 100644 _isWindows = (process.platform === 'win32'); _isMacintosh = (process.platform === 'darwin'); diff --git a/src/vs/base/node/languagePacks.js b/src/vs/base/node/languagePacks.js -index 3ae24454cb..d637d02855 100644 +index 3ae24454cb..fac8679290 100644 --- a/src/vs/base/node/languagePacks.js +++ b/src/vs/base/node/languagePacks.js -@@ -146,7 +146,7 @@ function factory(nodeRequire, path, fs, perf) { +@@ -146,7 +146,10 @@ function factory(nodeRequire, path, fs, perf) { function getLanguagePackConfigurations(userDataPath) { const configFile = path.join(userDataPath, 'languagepacks.json'); try { - return nodeRequire(configFile); ++ // NOTE@coder: Swapped require with readFile since require is cached and ++ // we don't restart the server-side portion of code-server when the ++ // language changes. + return JSON.parse(fs.readFileSync(configFile, "utf8")); } catch (err) { // Do nothing. If we can't read the file we have no // language pack config. -diff --git a/src/vs/code/browser/workbench/workbench.html b/src/vs/code/browser/workbench/workbench.html -index 44f67f0a0b..50d29b1e87 100644 ---- a/src/vs/code/browser/workbench/workbench.html -+++ b/src/vs/code/browser/workbench/workbench.html -@@ -18,10 +18,12 @@ - - - -+ - - -- -- -+ -+ -+ - - - -diff --git a/src/vs/code/browser/workbench/workbench.js b/src/vs/code/browser/workbench/workbench.js -index 2f09f53e43..0f5eef1c9e 100644 ---- a/src/vs/code/browser/workbench/workbench.js -+++ b/src/vs/code/browser/workbench/workbench.js -@@ -8,24 +8,53 @@ - - (function () { - -+ const basePath = window.location.pathname.replace(/\/+$/, ''); -+ const base = window.location.origin + basePath; -+ const options = JSON.parse(document.getElementById('vscode-workbench-web-configuration').getAttribute('data-settings')); -+ options.webviewEndpoint = `${base}/webview/`; -+ let nlsConfig; -+ try { -+ nlsConfig = JSON.parse(document.getElementById('vscode-remote-nls-configuration').getAttribute('data-settings')); -+ if (nlsConfig._resolvedLanguagePackCoreLocation) { -+ const bundles = Object.create(null); -+ nlsConfig.loadBundle = (bundle, language, cb) => { -+ let result = bundles[bundle]; -+ if (result) { -+ return cb(undefined, result); -+ } -+ // FIXME: Only works if path separators are /. -+ const path = nlsConfig._resolvedLanguagePackCoreLocation -+ + '/' + bundle.replace(/\//g, '!') + '.nls.json'; -+ fetch(`${base}/resource/?path=${encodeURIComponent(path)}`) -+ .then((response) => response.json()) -+ .then((json) => { -+ bundles[bundle] = json; -+ cb(undefined, json); -+ }) -+ .catch(cb); -+ }; -+ } -+ } catch (error) { /* Probably fine. */ } -+ - /** @type any */ - const amdLoader = require; - -+ const staticBase = base + `/static${options.productConfiguration && options.productConfiguration.commit ? `-${options.productConfiguration.commit}` : ''}`; - amdLoader.config({ -- baseUrl: `${window.location.origin}/static/out`, -+ baseUrl: `${staticBase}/out`, - paths: { -- 'vscode-textmate': `${window.location.origin}/static/node_modules/vscode-textmate/release/main`, -- 'onigasm-umd': `${window.location.origin}/static/node_modules/onigasm-umd/release/main`, -- 'xterm': `${window.location.origin}/static/node_modules/xterm/lib/xterm.js`, -- 'xterm-addon-search': `${window.location.origin}/static/node_modules/xterm-addon-search/lib/xterm-addon-search.js`, -- 'xterm-addon-web-links': `${window.location.origin}/static/node_modules/xterm-addon-web-links/lib/xterm-addon-web-links.js`, -- 'semver-umd': `${window.location.origin}/static/node_modules/semver-umd/lib/semver-umd.js`, -- '@microsoft/applicationinsights-web': `${window.location.origin}/static/node_modules/@microsoft/applicationinsights-web/dist/applicationinsights-web.js`, -- } -+ 'vscode-textmate': `${staticBase}/node_modules/vscode-textmate/release/main`, -+ 'onigasm-umd': `${staticBase}/node_modules/onigasm-umd/release/main`, -+ 'xterm': `${staticBase}/node_modules/xterm/lib/xterm.js`, -+ 'xterm-addon-search': `${staticBase}/node_modules/xterm-addon-search/lib/xterm-addon-search.js`, -+ 'xterm-addon-web-links': `${staticBase}/node_modules/xterm-addon-web-links/lib/xterm-addon-web-links.js`, -+ 'semver-umd': `${staticBase}/node_modules/semver-umd/lib/semver-umd.js`, -+ '@microsoft/applicationinsights-web': `${staticBase}/node_modules/@microsoft/applicationinsights-web/dist/applicationinsights-web.js`, -+ }, -+ 'vs/nls': nlsConfig - }); - - amdLoader(['vs/workbench/workbench.web.api'], function (api) { -- const options = JSON.parse(document.getElementById('vscode-workbench-web-configuration').getAttribute('data-settings')); - api.create(document.body, options); - }); - })(); diff --git a/src/vs/platform/environment/common/environment.ts b/src/vs/platform/environment/common/environment.ts -index 3b45568e1b..aebe04ccfe 100644 +index 990755c4f3..06449bb9cb 100644 --- a/src/vs/platform/environment/common/environment.ts +++ b/src/vs/platform/environment/common/environment.ts -@@ -82,6 +82,8 @@ export interface ParsedArgs { - - // Web flags - 'web-user-data-dir'?: string; -+ 'extra-extensions-dir'?: string | string[]; -+ 'extra-builtin-extensions-dir'?: string | string[]; - } - - export const IEnvironmentService = createDecorator('environmentService'); -@@ -162,4 +164,6 @@ export interface IEnvironmentService { +@@ -36,6 +36,8 @@ export interface ParsedArgs { + logExtensionHostCommunication?: boolean; + 'extensions-dir'?: string; + 'builtin-extensions-dir'?: string; ++ 'extra-extensions-dir'?: string[]; ++ 'extra-builtin-extensions-dir'?: string[]; + extensionDevelopmentPath?: string[]; // // undefined or array of 1 or more local paths or URIs + extensionTestsPath?: string; // either a local path or a URI + 'extension-development-confirm-save'?: boolean; +@@ -169,4 +171,6 @@ export interface IEnvironmentService { driverVerbose: boolean; galleryMachineIdResource?: URI; + extraExtensionPaths: string[]; + extraBuiltinExtensionPaths: string[]; } +diff --git a/src/vs/platform/environment/node/argv.ts b/src/vs/platform/environment/node/argv.ts +index 3e48fe4ddd..e0962b8736 100644 +--- a/src/vs/platform/environment/node/argv.ts ++++ b/src/vs/platform/environment/node/argv.ts +@@ -58,6 +58,8 @@ export const OPTIONS: OptionDescriptions> = { + + 'extensions-dir': { type: 'string', deprecates: 'extensionHomePath', cat: 'e', args: 'dir', description: localize('extensionHomePath', "Set the root path for extensions.") }, + 'builtin-extensions-dir': { type: 'string' }, ++ 'extra-builtin-extensions-dir': { type: 'string[]', cat: 'o', description: 'Path to an extra builtin extension directory.' }, ++ 'extra-extensions-dir': { type: 'string[]', cat: 'o', description: 'Path to an extra user extension directory.' }, + 'list-extensions': { type: 'boolean', cat: 'e', description: localize('listExtensions', "List the installed extensions.") }, + 'show-versions': { type: 'boolean', cat: 'e', description: localize('showVersions', "Show versions of installed extensions, when using --list-extension.") }, + 'category': { type: 'string', cat: 'e', description: localize('category', "Filters installed extensions by provided category, when using --list-extension.") }, diff --git a/src/vs/platform/environment/node/environmentService.ts b/src/vs/platform/environment/node/environmentService.ts -index a07c4c8f48..028ed19657 100644 +index f7d207009d..5c37b52dab 100644 --- a/src/vs/platform/environment/node/environmentService.ts +++ b/src/vs/platform/environment/node/environmentService.ts -@@ -264,6 +264,15 @@ export class EnvironmentService implements IEnvironmentService { +@@ -260,6 +260,12 @@ export class EnvironmentService implements IEnvironmentService { get driverHandle(): string | undefined { return this._args['driver']; } get driverVerbose(): boolean { return !!this._args['driver-verbose']; } + @memoize get extraExtensionPaths(): string[] { -+ return this.arrayify(this._args['extra-extensions-dir']).map((p) => parsePathArg(p, process)); ++ return (this._args['extra-extensions-dir'] || []).map((p) => parsePathArg(p, process)); + } + @memoize get extraBuiltinExtensionPaths(): string[] { -+ return this.arrayify(this._args['extra-builtin-extensions-dir']).map((p) => parsePathArg(p, process)); -+ } -+ private arrayify(arg: T | T[] = []): T[] { -+ return (Array.isArray(arg) ? arg : [arg]).filter((p) => !!p); ++ return (this._args['extra-builtin-extensions-dir'] || []).map((p) => parsePathArg(p, process)); + } constructor(private _args: ParsedArgs, private _execPath: string) { if (!process.env['VSCODE_LOGS']) { diff --git a/src/vs/platform/extensionManagement/node/extensionManagementService.ts b/src/vs/platform/extensionManagement/node/extensionManagementService.ts -index 7d0b568fc7..23ab257b42 100644 +index f0eaa74a59..3abf9e1752 100644 --- a/src/vs/platform/extensionManagement/node/extensionManagementService.ts +++ b/src/vs/platform/extensionManagement/node/extensionManagementService.ts @@ -731,11 +731,15 @@ export class ExtensionManagementService extends Disposable implements IExtension @@ -291,7 +135,7 @@ index 7d0b568fc7..23ab257b42 100644 + .map((path) => this.scanExtensions(path, ExtensionType.System)) + ]).then((results) => { + const result = results.reduce((flat, current) => flat.concat(current), []); -+ this.logService.info('Scanned system extensions:', result.length); ++ this.logService.trace('Scanned system extensions:', result.length); + return result; + }); if (this.environmentService.isBuilt) { @@ -346,167 +190,113 @@ index 7d0b568fc7..23ab257b42 100644 .then(extensions => { const toRemove: ILocalExtension[] = []; -diff --git a/src/vs/platform/localizations/electron-browser/localizationsService.ts b/src/vs/platform/localizations/electron-browser/localizationsService.ts -index add4dfb2fc..18fc71df51 100644 ---- a/src/vs/platform/localizations/electron-browser/localizationsService.ts -+++ b/src/vs/platform/localizations/electron-browser/localizationsService.ts -@@ -6,7 +6,7 @@ - import { IChannel } from 'vs/base/parts/ipc/common/ipc'; - import { Event } from 'vs/base/common/event'; - import { ILocalizationsService, LanguageType } from 'vs/platform/localizations/common/localizations'; --import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService'; -+import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; - import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; - - export class LocalizationsService implements ILocalizationsService { -@@ -15,8 +15,8 @@ export class LocalizationsService implements ILocalizationsService { - - private channel: IChannel; - -- constructor(@ISharedProcessService sharedProcessService: ISharedProcessService) { -- this.channel = sharedProcessService.getChannel('localizations'); -+ constructor(@IRemoteAgentService remoteAgentService: IRemoteAgentService) { -+ this.channel = remoteAgentService.getConnection()!.getChannel('localizations'); +diff --git a/src/vs/platform/product/common/product.ts b/src/vs/platform/product/common/product.ts +index 2de51e8d32..837770990e 100644 +--- a/src/vs/platform/product/common/product.ts ++++ b/src/vs/platform/product/common/product.ts +@@ -22,10 +22,16 @@ if (isWeb) { + if (Object.keys(product).length === 0) { + assign(product, { + version: '1.39.0-dev', ++ codeServerVersion: 'dev', + nameLong: 'Visual Studio Code Web Dev', + nameShort: 'VSCode Web Dev' + }); } - - get onDidLanguagesChange(): Event { return this.channel.listen('onDidLanguagesChange'); } -diff --git a/src/vs/platform/log/common/logIpc.ts b/src/vs/platform/log/common/logIpc.ts -index 9f68b645b6..1e224cc29a 100644 ---- a/src/vs/platform/log/common/logIpc.ts -+++ b/src/vs/platform/log/common/logIpc.ts -@@ -26,6 +26,7 @@ export class LogLevelSetterChannel implements IServerChannel { - call(_: unknown, command: string, arg?: any): Promise { - switch (command) { - case 'setLevel': this.service.setLevel(arg); return Promise.resolve(); -+ case 'getLevel': return Promise.resolve(this.service.getLevel()); - } - - throw new Error(`Call not found: ${command}`); -@@ -43,6 +44,10 @@ export class LogLevelSetterChannelClient { - setLevel(level: LogLevel): void { - this.channel.call('setLevel', level); - } -+ -+ getLevel(): Promise { -+ return this.channel.call('getLevel'); ++ const el = document.getElementById('vscode-remote-product-configuration'); ++ const rawProductConfiguration = el && el.getAttribute('data-settings'); ++ if (rawProductConfiguration) { ++ assign(product, JSON.parse(rawProductConfiguration)); + } } - export class FollowerLogService extends DelegatedLogService implements ILogService { -diff --git a/src/vs/platform/product/node/package.ts b/src/vs/platform/product/node/package.ts -index d39c5877d6..c189d6f19f 100644 ---- a/src/vs/platform/product/node/package.ts -+++ b/src/vs/platform/product/node/package.ts -@@ -9,6 +9,7 @@ import { getPathFromAmdModule } from 'vs/base/common/amd'; - export interface IPackageConfiguration { - name: string; - version: string; -+ codeServerVersion: string; + // Node: AMD loader +@@ -35,7 +41,7 @@ else if (typeof require !== 'undefined' && typeof require.__$__nodeRequire === ' + const rootPath = path.dirname(getPathFromAmdModule(require, '')); + + product = assign({}, require.__$__nodeRequire(path.join(rootPath, 'product.json')) as IProductConfiguration); +- const pkg = require.__$__nodeRequire(path.join(rootPath, 'package.json')) as { version: string; }; ++ const pkg = require.__$__nodeRequire(path.join(rootPath, 'package.json')) as { version: string; codeServerVersion: string; }; + + // Running out of sources + if (env['VSCODE_DEV']) { +@@ -47,7 +53,8 @@ else if (typeof require !== 'undefined' && typeof require.__$__nodeRequire === ' + } + + assign(product, { +- version: pkg.version ++ version: pkg.version, ++ codeServerVersion: pkg.codeServerVersion, + }); } - const rootPath = path.dirname(getPathFromAmdModule(require, '')); +diff --git a/src/vs/platform/product/common/productService.ts b/src/vs/platform/product/common/productService.ts +index 5aa5c32d7e..e4e7fd4174 100644 +--- a/src/vs/platform/product/common/productService.ts ++++ b/src/vs/platform/product/common/productService.ts +@@ -15,6 +15,7 @@ export interface IProductService extends Readonly { + + export interface IProductConfiguration { + readonly version: string; ++ readonly codeServerVersion: string; + readonly date?: string; + readonly quality?: string; + readonly commit?: string; diff --git a/src/vs/platform/remote/browser/browserSocketFactory.ts b/src/vs/platform/remote/browser/browserSocketFactory.ts -index 6b24ec0781..43dd9c12c8 100644 +index d0f6e6b18a..1966fd297d 100644 --- a/src/vs/platform/remote/browser/browserSocketFactory.ts +++ b/src/vs/platform/remote/browser/browserSocketFactory.ts -@@ -133,7 +133,7 @@ export class BrowserSocketFactory implements ISocketFactory { +@@ -205,7 +205,8 @@ export class BrowserSocketFactory implements ISocketFactory { } connect(host: string, port: number, query: string, callback: IConnectCallback): void { - const socket = this._webSocketFactory.create(`ws://${host}:${port}/?${query}&skipWebSocketFrames=false`); ++ // NOTE@coder: Modified to work against the current path. + const socket = this._webSocketFactory.create(`${window.location.protocol === 'https:' ? 'wss' : 'ws'}://${window.location.host}${window.location.pathname}?${query}&skipWebSocketFrames=false`); const errorListener = socket.onError((err) => callback(err, undefined)); socket.onOpen(() => { errorListener.dispose(); -@@ -141,6 +141,3 @@ export class BrowserSocketFactory implements ISocketFactory { +@@ -213,6 +214,3 @@ export class BrowserSocketFactory implements ISocketFactory { }); } } - - - -diff --git a/src/vs/platform/update/electron-browser/updateService.ts b/src/vs/platform/update/electron-browser/updateService.ts -index bd8fa6cc18..cf6108a57b 100644 ---- a/src/vs/platform/update/electron-browser/updateService.ts -+++ b/src/vs/platform/update/electron-browser/updateService.ts -@@ -6,7 +6,7 @@ - import { IChannel } from 'vs/base/parts/ipc/common/ipc'; - import { Event, Emitter } from 'vs/base/common/event'; - import { IUpdateService, State } from 'vs/platform/update/common/update'; --import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService'; -+import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; - import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; - - export class UpdateService implements IUpdateService { -@@ -21,8 +21,8 @@ export class UpdateService implements IUpdateService { - - private channel: IChannel; - -- constructor(@IMainProcessService mainProcessService: IMainProcessService) { -- this.channel = mainProcessService.getChannel('update'); -+ constructor(@IRemoteAgentService mainProcessService: IRemoteAgentService) { -+ this.channel = mainProcessService.getConnection()!.getChannel('update'); - - // always set this._state as the state changes - this.onStateChange(state => this._state = state); diff --git a/src/vs/platform/update/electron-main/abstractUpdateService.ts b/src/vs/platform/update/electron-main/abstractUpdateService.ts -index d789bf4e09..e25c9c9d6a 100644 +index 8a1c95d37b..8225a85d47 100644 --- a/src/vs/platform/update/electron-main/abstractUpdateService.ts +++ b/src/vs/platform/update/electron-main/abstractUpdateService.ts @@ -6,7 +6,6 @@ import { Event, Emitter } from 'vs/base/common/event'; import { timeout } from 'vs/base/common/async'; import { IConfigurationService, getMigratedSettingValue } from 'vs/platform/configuration/common/configuration'; --import { ILifecycleService } from 'vs/platform/lifecycle/electron-main/lifecycleMain'; - import product from 'vs/platform/product/node/product'; +-import { ILifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; + import product from 'vs/platform/product/common/product'; import { IUpdateService, State, StateType, AvailableForDownload, UpdateType } from 'vs/platform/update/common/update'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; @@ -44,7 +43,7 @@ export abstract class AbstractUpdateService implements IUpdateService { } constructor( -- @ILifecycleService private readonly lifecycleService: ILifecycleService, -+ _placeholder: any, // To prevent errors from the extending classes. +- @ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService, ++ _: any, // NOTE@coder: This depends on Electron so we skip it. @IConfigurationService protected configurationService: IConfigurationService, @IEnvironmentService private readonly environmentService: IEnvironmentService, @IRequestService protected requestService: IRequestService, -@@ -55,7 +54,7 @@ export abstract class AbstractUpdateService implements IUpdateService { - return; - } - -- if (!product.updateUrl || !product.commit) { -+ if (!product.commit) { - this.logService.info('update#ctor - updates are disabled as there is no update URL'); - return; - } -@@ -93,7 +92,7 @@ export abstract class AbstractUpdateService implements IUpdateService { - } - - private getProductQuality(updateMode: string): string | undefined { -- return updateMode === 'none' ? undefined : product.quality; -+ return updateMode === 'none' ? undefined : 'unused'; - } - - private scheduleCheckForUpdates(delay = 60 * 60 * 1000): Promise { -@@ -152,15 +151,15 @@ export abstract class AbstractUpdateService implements IUpdateService { +@@ -152,15 +151,8 @@ export abstract class AbstractUpdateService implements IUpdateService { this.logService.trace('update#quitAndInstall(): before lifecycle quit()'); -- this.lifecycleService.quit(true /* from update */).then(vetod => { +- this.lifecycleMainService.quit(true /* from update */).then(vetod => { - this.logService.trace(`update#quitAndInstall(): after lifecycle quit() with veto: ${vetod}`); - if (vetod) { - return; - } -+ // this.lifecycleService.quit(true /* from update */).then(vetod => { -+ // this.logService.trace(`update#quitAndInstall(): after lifecycle quit() with veto: ${vetod}`); -+ // if (vetod) { -+ // return; -+ // } - +- this.logService.trace('update#quitAndInstall(): running raw#quitAndInstall()'); this.doQuitAndInstall(); - }); -+ // }); return Promise.resolve(undefined); } @@ -523,10 +313,10 @@ index 2905c52411..303ddf211f 100644 export class ExtensionPoints implements IWorkbenchContribution { diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts -index c5fd74ffe7..e972b03f79 100644 +index 230d09a290..84753e6ac7 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts -@@ -68,6 +68,7 @@ import { ILogService } from 'vs/platform/log/common/log'; +@@ -67,6 +67,7 @@ import { ILogService } from 'vs/platform/log/common/log'; import { IURITransformerService } from 'vs/workbench/api/common/extHostUriTransformerService'; import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService'; import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService'; @@ -534,7 +324,7 @@ index c5fd74ffe7..e972b03f79 100644 export interface IExtensionApiFactory { (extension: IExtensionDescription, registry: ExtensionDescriptionRegistry, configProvider: ExtHostConfigProvider): typeof vscode; -@@ -87,6 +88,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I +@@ -86,6 +87,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I const rpcProtocol = accessor.get(IExtHostRpcService); const extHostStorage = accessor.get(IExtHostStorage); const extHostLogService = accessor.get(ILogService); @@ -542,7 +332,7 @@ index c5fd74ffe7..e972b03f79 100644 // register addressable instances rpcProtocol.set(ExtHostContext.ExtHostLogService, extHostLogService); -@@ -94,6 +96,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I +@@ -93,6 +95,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I rpcProtocol.set(ExtHostContext.ExtHostConfiguration, extHostConfiguration); rpcProtocol.set(ExtHostContext.ExtHostExtensionService, extensionService); rpcProtocol.set(ExtHostContext.ExtHostStorage, extHostStorage); @@ -551,10 +341,10 @@ index c5fd74ffe7..e972b03f79 100644 // automatically create and register addressable instances const extHostDecorations = rpcProtocol.set(ExtHostContext.ExtHostDecorations, accessor.get(IExtHostDecorations)); diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts -index a6ac9b8086..c0027b8f74 100644 +index 7bd6aa6cb7..7c28136366 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts -@@ -614,6 +614,10 @@ export interface MainThreadLabelServiceShape extends IDisposable { +@@ -627,6 +627,10 @@ export interface MainThreadLabelServiceShape extends IDisposable { $unregisterResourceLabelFormatter(handle: number): void; } @@ -565,7 +355,7 @@ index a6ac9b8086..c0027b8f74 100644 export interface MainThreadSearchShape extends IDisposable { $registerFileSearchProvider(handle: number, scheme: string): void; $registerTextSearchProvider(handle: number, scheme: string): void; -@@ -844,6 +848,13 @@ export interface ExtHostLabelServiceShape { +@@ -860,6 +864,13 @@ export interface ExtHostLabelServiceShape { $registerResourceLabelFormatter(formatter: ResourceLabelFormatter): IDisposable; } @@ -579,7 +369,7 @@ index a6ac9b8086..c0027b8f74 100644 export interface ExtHostSearchShape { $provideFileSearchResults(handle: number, session: number, query: search.IRawQuery, token: CancellationToken): Promise; $provideTextSearchResults(handle: number, session: number, query: search.IRawTextQuery, token: CancellationToken): Promise; -@@ -1351,7 +1362,8 @@ export const MainContext = { +@@ -1384,7 +1395,8 @@ export const MainContext = { MainThreadSearch: createMainId('MainThreadSearch'), MainThreadTask: createMainId('MainThreadTask'), MainThreadWindow: createMainId('MainThreadWindow'), @@ -589,7 +379,7 @@ index a6ac9b8086..c0027b8f74 100644 }; export const ExtHostContext = { -@@ -1385,5 +1397,6 @@ export const ExtHostContext = { +@@ -1418,5 +1430,6 @@ export const ExtHostContext = { ExtHostStorage: createMainId('ExtHostStorage'), ExtHostUrls: createExtId('ExtHostUrls'), ExtHostOutputService: createMainId('ExtHostOutputService'), @@ -598,7 +388,7 @@ index a6ac9b8086..c0027b8f74 100644 + ExtHostNodeProxy: createMainId('ExtHostNodeProxy') }; diff --git a/src/vs/workbench/api/common/extHostExtensionService.ts b/src/vs/workbench/api/common/extHostExtensionService.ts -index 8c903a6027..7199c1e467 100644 +index b5ce835e07..22be8516c1 100644 --- a/src/vs/workbench/api/common/extHostExtensionService.ts +++ b/src/vs/workbench/api/common/extHostExtensionService.ts @@ -5,7 +5,7 @@ @@ -618,7 +408,7 @@ index 8c903a6027..7199c1e467 100644 interface ITestRunner { /** Old test runner API, as exported from `vscode/lib/testrunner` */ -@@ -75,6 +76,7 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio +@@ -76,6 +77,7 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio protected readonly _extHostWorkspace: ExtHostWorkspace; protected readonly _extHostConfiguration: ExtHostConfiguration; protected readonly _logService: ILogService; @@ -626,7 +416,7 @@ index 8c903a6027..7199c1e467 100644 protected readonly _mainThreadWorkspaceProxy: MainThreadWorkspaceShape; protected readonly _mainThreadTelemetryProxy: MainThreadTelemetryShape; -@@ -103,7 +105,8 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio +@@ -104,7 +106,8 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio @IExtHostConfiguration extHostConfiguration: IExtHostConfiguration, @ILogService logService: ILogService, @IExtHostInitDataService initData: IExtHostInitDataService, @@ -636,7 +426,7 @@ index 8c903a6027..7199c1e467 100644 ) { this._hostUtils = hostUtils; this._extHostContext = extHostContext; -@@ -112,6 +115,7 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio +@@ -113,6 +116,7 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio this._extHostWorkspace = extHostWorkspace; this._extHostConfiguration = extHostConfiguration; this._logService = logService; @@ -644,17 +434,15 @@ index 8c903a6027..7199c1e467 100644 this._disposables = new DisposableStore(); this._mainThreadWorkspaceProxy = this._extHostContext.getProxy(MainContext.MainThreadWorkspace); -@@ -331,15 +335,15 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio - this._logService.info(`ExtensionService#_doActivateExtension ${extensionDescription.identifier.value} ${JSON.stringify(reason)}`); +@@ -331,14 +335,14 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio const activationTimesBuilder = new ExtensionActivationTimesBuilder(reason.startup); -- return Promise.all([ -- this._loadCommonJSModule(joinPath(extensionDescription.extensionLocation, extensionDescription.main), activationTimesBuilder), -+ return Promise.all([ + return Promise.all([ +- this._loadCommonJSModule(joinPath(extensionDescription.extensionLocation, extensionDescription.main), activationTimesBuilder), + this._loadCommonJSModule(extensionDescription, activationTimesBuilder), this._loadExtensionContext(extensionDescription) ]).then(values => { - return AbstractExtHostExtensionService._callActivate(this._logService, extensionDescription.identifier, values[0], values[1], activationTimesBuilder); + return AbstractExtHostExtensionService._callActivate(this._logService, extensionDescription.identifier, values[0], values[1], activationTimesBuilder); }); } @@ -697,7 +485,7 @@ index a227d8a67b..92553a976c 100644 +} +registerSingleton(IExtHostNodeProxy, class extends NotImplementedProxy(IExtHostNodeProxy) {}); diff --git a/src/vs/workbench/api/node/extHostExtensionService.ts b/src/vs/workbench/api/node/extHostExtensionService.ts -index 8e96e6738e..5a3a48101a 100644 +index 49a8e254fd..99d233aed5 100644 --- a/src/vs/workbench/api/node/extHostExtensionService.ts +++ b/src/vs/workbench/api/node/extHostExtensionService.ts @@ -13,6 +13,8 @@ import { ExtHostDownloadService } from 'vs/workbench/api/node/extHostDownloadSer @@ -722,24 +510,25 @@ index 8e96e6738e..5a3a48101a 100644 throw new Error(`Cannot load URI: '${module}', must be of file-scheme`); } diff --git a/src/vs/workbench/api/worker/extHostExtensionService.ts b/src/vs/workbench/api/worker/extHostExtensionService.ts -index 4fcb6db76f..b6c92528f4 100644 +index afd82468c0..67d938e9ab 100644 --- a/src/vs/workbench/api/worker/extHostExtensionService.ts +++ b/src/vs/workbench/api/worker/extHostExtensionService.ts -@@ -10,6 +10,9 @@ import { endsWith, startsWith } from 'vs/base/common/strings'; +@@ -9,6 +9,10 @@ import { AbstractExtHostExtensionService } from 'vs/workbench/api/common/extHost + import { endsWith } from 'vs/base/common/strings'; import { URI } from 'vs/base/common/uri'; - import { joinPath } from 'vs/base/common/resources'; import { RequireInterceptor } from 'vs/workbench/api/common/extHostRequireInterceptor'; ++import { joinPath } from 'vs/base/common/resources'; +import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; +import { fromTar } from 'vs/server/node_modules/@coder/requirefs/out/requirefs'; +import { Client } from 'vs/server/node_modules/@coder/node-browser/out/client/client'; - class ExportsTrap { + class WorkerRequireInterceptor extends RequireInterceptor { -@@ -105,7 +108,44 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService { +@@ -41,7 +45,48 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService { await this._fakeModules.install(); } -- protected _loadCommonJSModule(module: URI, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise { +- protected async _loadCommonJSModule(module: URI, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise { + protected async _loadCommonJSModule(module: URI | IExtensionDescription, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise { + if (!URI.isUri(module) && module.extensionKind !== 'web') { + const fetchUri = URI.from({ @@ -778,37 +567,40 @@ index 4fcb6db76f..b6c92528f4 100644 + }); + return rfs.require('.'); + } - - (self).window = self; // <- that's improper but might help extensions that aren't authored correctly - -@@ -132,6 +172,9 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService { - - return trap.claim(); - }; ++ + if (!URI.isUri(module)) { + module = joinPath(module.extensionLocation, module.main!); + } - try { - activationTimesBuilder.codeLoadingStart(); + module = module.with({ path: ensureSuffix(module.path, '.js') }); + const response = await fetch(module.toString(true)); +@@ -57,7 +102,7 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService { + const _exports = {}; + const _module = { exports: _exports }; + const _require = (request: string) => { +- const result = this._fakeModules.getModule(request, module); ++ const result = this._fakeModules.getModule(request, module); + if (result === undefined) { + throw new Error(`Cannot load module '${request}'`); + } diff --git a/src/vs/workbench/browser/dnd.ts b/src/vs/workbench/browser/dnd.ts -index b99f800164..bf44f1d9c4 100644 +index 005a025aa9..ab392630c0 100644 --- a/src/vs/workbench/browser/dnd.ts +++ b/src/vs/workbench/browser/dnd.ts -@@ -32,6 +32,7 @@ import { IRecentFile } from 'vs/platform/history/common/history'; - import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing'; +@@ -32,6 +32,7 @@ import { IWorkspaceEditingService } from 'vs/workbench/services/workspaces/commo import { withNullAsUndefined } from 'vs/base/common/types'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; + import { IHostService } from 'vs/workbench/services/host/browser/host'; +import { IUploadService } from 'vs/server/src/browser/upload'; export interface IDraggedResource { resource: URI; -@@ -166,14 +167,15 @@ export class ResourcesDropHandler { - @IUntitledEditorService private readonly untitledEditorService: IUntitledEditorService, +@@ -167,14 +168,15 @@ export class ResourcesDropHandler { @IEditorService private readonly editorService: IEditorService, @IConfigurationService private readonly configurationService: IConfigurationService, -- @IWorkspaceEditingService private readonly workspaceEditingService: IWorkspaceEditingService -+ @IWorkspaceEditingService private readonly workspaceEditingService: IWorkspaceEditingService, + @IWorkspaceEditingService private readonly workspaceEditingService: IWorkspaceEditingService, +- @IHostService private readonly hostService: IHostService ++ @IHostService private readonly hostService: IHostService, + @IUploadService private readonly uploadService: IUploadService, ) { } @@ -821,57 +613,27 @@ index b99f800164..bf44f1d9c4 100644 } // Make the window active to handle the drop properly within -diff --git a/src/vs/workbench/browser/layout.ts b/src/vs/workbench/browser/layout.ts -index 2e1e63986f..563c4b2472 100644 ---- a/src/vs/workbench/browser/layout.ts -+++ b/src/vs/workbench/browser/layout.ts -@@ -260,7 +260,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi - if (visible !== this.state.menuBar.toggled) { - this.state.menuBar.toggled = visible; - -- if (this.state.fullscreen && (this.state.menuBar.visibility === 'toggle' || this.state.menuBar.visibility === 'default')) { -+ if (this.state.menuBar.visibility === 'toggle' || (this.state.fullscreen && this.state.menuBar.visibility === 'default')) { - this._onTitleBarVisibilityChange.fire(); - - if (this.workbenchGrid instanceof SerializableGrid) { -@@ -563,13 +563,13 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi - case Parts.TITLEBAR_PART: - if (getTitleBarStyle(this.configurationService, this.environmentService) === 'native') { - return false; -- } else if (!this.state.fullscreen) { -- return true; -+ } else if (this.state.menuBar.visibility === 'default') { -+ return !this.state.fullscreen || this.state.menuBar.toggled; - } else if (isMacintosh && isNative) { - return false; - } else if (this.state.menuBar.visibility === 'visible') { - return true; -- } else if (this.state.menuBar.visibility === 'toggle' || this.state.menuBar.visibility === 'default') { -+ } else if (this.state.menuBar.visibility === 'toggle') { - return this.state.menuBar.toggled; - } - diff --git a/src/vs/workbench/browser/web.main.ts b/src/vs/workbench/browser/web.main.ts -index f5944ce974..66bedce55c 100644 +index 84c46faa36..957e8412e1 100644 --- a/src/vs/workbench/browser/web.main.ts +++ b/src/vs/workbench/browser/web.main.ts -@@ -45,6 +45,7 @@ import { FileLogService } from 'vs/platform/log/common/fileLogService'; - import { toLocalISOString } from 'vs/base/common/date'; +@@ -48,6 +48,7 @@ import { toLocalISOString } from 'vs/base/common/date'; import { IndexedDBLogProvider } from 'vs/workbench/services/log/browser/indexedDBLogProvider'; import { InMemoryLogProvider } from 'vs/workbench/services/log/common/inMemoryLogProvider'; + import { isWorkspaceToOpen, isFolderToOpen } from 'vs/platform/windows/common/windows'; +import { initialize } from 'vs/server/src/browser/client'; - class CodeRendererMain extends Disposable { + class BrowserMain extends Disposable { -@@ -94,6 +95,7 @@ class CodeRendererMain extends Disposable { +@@ -84,6 +85,7 @@ class BrowserMain extends Disposable { // Startup workbench.startup(); + await initialize(services.serviceCollection); } - private restoreBaseTheme(): void { -@@ -204,6 +206,7 @@ class CodeRendererMain extends Disposable { + private registerListeners(workbench: Workbench, storageService: BrowserStorageService): void { +@@ -238,6 +240,7 @@ class BrowserMain extends Disposable { const channel = connection.getChannel(REMOTE_FILE_SYSTEM_CHANNEL_NAME); const remoteFileSystemProvider = this._register(new RemoteExtensionsFileSystemProvider(channel, remoteAgentService.getEnvironment())); fileService.registerProvider(Schemas.vscodeRemote, remoteFileSystemProvider); @@ -879,69 +641,11 @@ index f5944ce974..66bedce55c 100644 if (!this.configuration.userDataProvider) { const remoteUserDataUri = this.getRemoteUserDataUri(); -diff --git a/src/vs/workbench/browser/web.simpleservices.ts b/src/vs/workbench/browser/web.simpleservices.ts -index 895a8a0393..e9fa627fba 100644 ---- a/src/vs/workbench/browser/web.simpleservices.ts -+++ b/src/vs/workbench/browser/web.simpleservices.ts -@@ -33,6 +33,7 @@ import { localize } from 'vs/nls'; - import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; - // tslint:disable-next-line: import-patterns - import { IWorkspaceStatsService, Tags } from 'vs/workbench/contrib/stats/common/workspaceStats'; -+import { withQuery } from 'vs/server/src/browser/client'; - - //#region Update - -@@ -64,7 +65,7 @@ export class SimpleUpdateService implements IUpdateService { - } - } - --registerSingleton(IUpdateService, SimpleUpdateService); -+// registerSingleton(IUpdateService, SimpleUpdateService); - - //#endregion - -@@ -285,7 +286,10 @@ export class SimpleWindowService extends Disposable implements IWindowService { - for (let i = 0; i < _uris.length; i++) { - const uri = _uris[i]; - if ('folderUri' in uri) { -- const newAddress = `${document.location.origin}/?folder=${uri.folderUri.path}`; -+ const newAddress = withQuery(window.location.toString(), { -+ folder: uri.folderUri.path, -+ workspace: undefined, -+ }); - if (openFolderInNewWindow) { - window.open(newAddress); - } else { -@@ -293,7 +297,10 @@ export class SimpleWindowService extends Disposable implements IWindowService { - } - } - if ('workspaceUri' in uri) { -- const newAddress = `${document.location.origin}/?workspace=${uri.workspaceUri.path}`; -+ const newAddress = withQuery(window.location.toString(), { -+ folder: undefined, -+ workspace: uri.workspaceUri.path, -+ }); - if (openFolderInNewWindow) { - window.open(newAddress); - } else { -diff --git a/src/vs/workbench/buildfile.web.js b/src/vs/workbench/buildfile.web.js -index 47a8453302..4a7a8c7775 100644 ---- a/src/vs/workbench/buildfile.web.js -+++ b/src/vs/workbench/buildfile.web.js -@@ -20,5 +20,8 @@ function createModuleDescription(name, exclude) { - exports.collectModules = function () { - return [ - createModuleDescription('vs/workbench/contrib/output/common/outputLinkComputer', ['vs/base/common/worker/simpleWorker', 'vs/editor/common/services/editorSimpleWorker']), -+ createModuleDescription('vs/platform/files/node/watcher/unix/watcherApp', []), -+ createModuleDescription('vs/platform/files/node/watcher/nsfw/watcherApp', []), -+ createModuleDescription('vs/workbench/services/extensions/node/extensionHostProcess', []), - ]; - }; diff --git a/src/vs/workbench/contrib/files/browser/files.contribution.ts b/src/vs/workbench/contrib/files/browser/files.contribution.ts -index 19fcd5b0ac..30df54ac1a 100644 +index 1f4cd95f65..061931cbde 100644 --- a/src/vs/workbench/contrib/files/browser/files.contribution.ts +++ b/src/vs/workbench/contrib/files/browser/files.contribution.ts -@@ -224,7 +224,7 @@ configurationRegistry.registerConfiguration({ +@@ -209,7 +209,7 @@ configurationRegistry.registerConfiguration({ 'files.exclude': { 'type': 'object', 'markdownDescription': nls.localize('exclude', "Configure glob patterns for excluding files and folders. For example, the files explorer decides which files and folders to show or hide based on this setting. Read more about glob patterns [here](https://code.visualstudio.com/docs/editor/codebasics#_advanced-search-options)."), @@ -951,7 +655,7 @@ index 19fcd5b0ac..30df54ac1a 100644 'additionalProperties': { 'anyOf': [ diff --git a/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts b/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts -index 0c368120df..6396d2316b 100644 +index cc4bcb28c5..98679a8b32 100644 --- a/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts +++ b/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts @@ -47,6 +47,7 @@ import { IWorkspaceFolderCreationData } from 'vs/platform/workspaces/common/work @@ -962,362 +666,51 @@ index 0c368120df..6396d2316b 100644 export class ExplorerDelegate implements IListVirtualDelegate { -@@ -450,7 +451,8 @@ export class FileDragAndDrop implements ITreeDragAndDrop { +@@ -444,7 +445,8 @@ export class FileDragAndDrop implements ITreeDragAndDrop { @IInstantiationService private instantiationService: IInstantiationService, @ITextFileService private textFileService: ITextFileService, - @IWindowService private windowService: IWindowService, + @IHostService private hostService: IHostService, - @IWorkspaceEditingService private workspaceEditingService: IWorkspaceEditingService + @IWorkspaceEditingService private workspaceEditingService: IWorkspaceEditingService, + @IUploadService private readonly uploadService: IUploadService, ) { this.toDispose = []; -@@ -612,6 +614,7 @@ export class FileDragAndDrop implements ITreeDragAndDrop { - +@@ -605,6 +607,7 @@ export class FileDragAndDrop implements ITreeDragAndDrop { + } private async handleExternalDrop(data: DesktopDragAndDropData, target: ExplorerItem, originalEvent: DragEvent): Promise { + return this.uploadService.handleExternalDrop(data, target, originalEvent); const droppedResources = extractResources(originalEvent, true); // Check for dropped external files to be folders const result = await this.fileService.resolveAll(droppedResources); -diff --git a/src/vs/workbench/contrib/remote/common/remote.contribution.ts b/src/vs/workbench/contrib/remote/common/remote.contribution.ts -index 404f5a2a78..a04c825fa2 100644 ---- a/src/vs/workbench/contrib/remote/common/remote.contribution.ts -+++ b/src/vs/workbench/contrib/remote/common/remote.contribution.ts -@@ -79,7 +79,8 @@ class RemoteChannelsContribution extends Disposable implements IWorkbenchContrib - const connection = remoteAgentService.getConnection(); - if (connection) { - const logLevelClient = new LogLevelSetterChannelClient(connection.getChannel('loglevel')); -- logLevelClient.setLevel(logService.getLevel()); -+ logLevelClient.getLevel().then((level) => logService.setLevel(level)); -+ logLevelClient.onDidChangeLogLevel((level) => logService.setLevel(level)); - this._register(logService.onDidChangeLogLevel(level => logLevelClient.setLevel(level))); - } - } -diff --git a/src/vs/workbench/contrib/resources/browser/resourceServiceWorker.ts b/src/vs/workbench/contrib/resources/browser/resourceServiceWorker.ts -index 3534ef147d..773f711863 100644 ---- a/src/vs/workbench/contrib/resources/browser/resourceServiceWorker.ts -+++ b/src/vs/workbench/contrib/resources/browser/resourceServiceWorker.ts -@@ -34,7 +34,8 @@ self.addEventListener('activate', event => { - //#region --- fetching/caching - - const _cacheName = 'vscode-extension-resources'; --const _resourcePrefix = '/vscode-remote-resource'; -+const rootPath = (self).location.pathname.replace(/\/out\/vs\/workbench\/contrib\/resources\/browser\/resourceServiceWorkerMain.js$/, ''); -+const _resourcePrefix = `${rootPath}/vscode-remote-resources`; - const _pendingFetch = new Map(); - - self.addEventListener('message', event => { -diff --git a/src/vs/workbench/contrib/resources/browser/resourceServiceWorkerClient.ts b/src/vs/workbench/contrib/resources/browser/resourceServiceWorkerClient.ts -index 326dfb49ee..adf72747bd 100644 ---- a/src/vs/workbench/contrib/resources/browser/resourceServiceWorkerClient.ts -+++ b/src/vs/workbench/contrib/resources/browser/resourceServiceWorkerClient.ts -@@ -18,7 +18,11 @@ class ResourceServiceWorker { - constructor( - @ILogService private readonly _logService: ILogService, - ) { -- navigator.serviceWorker.register(ResourceServiceWorker._url, { scope: '/' }).then(reg => { -+ if (!navigator.serviceWorker) { -+ console.warn('Service workers are not enabled.'); -+ return; -+ } -+ navigator.serviceWorker.register(ResourceServiceWorker._url, { scope: window.location.pathname.replace(/\/+$/, '') }).then(reg => { - this._logService.trace('SW#reg', reg); - return reg.update(); - }).then(() => { -@@ -45,5 +49,3 @@ Registry.as(Extensions.Workbench).registerWorkb - ResourceServiceWorker, - LifecyclePhase.Ready - ); -- -- -diff --git a/src/vs/workbench/contrib/update/electron-browser/update.contribution.ts b/src/vs/workbench/contrib/update/electron-browser/update.contribution.ts -index e39fa57979..c7e1113846 100644 ---- a/src/vs/workbench/contrib/update/electron-browser/update.contribution.ts -+++ b/src/vs/workbench/contrib/update/electron-browser/update.contribution.ts -@@ -4,26 +4,11 @@ - *--------------------------------------------------------------------------------------------*/ - - import 'vs/platform/update/node/update.config.contribution'; --import * as platform from 'vs/base/common/platform'; - import { Registry } from 'vs/platform/registry/common/platform'; - import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; --import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; --import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; --import { ShowCurrentReleaseNotesAction, ProductContribution, UpdateContribution, Win3264BitContribution } from './update'; - import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; -+import { UpdateContribution } from 'vs/workbench/contrib/update/electron-browser/update'; - - const workbench = Registry.as(WorkbenchExtensions.Workbench); - --workbench.registerWorkbenchContribution(ProductContribution, LifecyclePhase.Restored); -- --if (platform.isWindows) { -- if (process.arch === 'ia32') { -- workbench.registerWorkbenchContribution(Win3264BitContribution, LifecyclePhase.Restored); -- } --} -- - workbench.registerWorkbenchContribution(UpdateContribution, LifecyclePhase.Restored); -- --// Editor --Registry.as(ActionExtensions.WorkbenchActions) -- .registerWorkbenchAction(new SyncActionDescriptor(ShowCurrentReleaseNotesAction, ShowCurrentReleaseNotesAction.ID, ShowCurrentReleaseNotesAction.LABEL), 'Show Release Notes'); -diff --git a/src/vs/workbench/contrib/update/electron-browser/update.ts b/src/vs/workbench/contrib/update/electron-browser/update.ts -index d429d21347..32559b70f0 100644 ---- a/src/vs/workbench/contrib/update/electron-browser/update.ts -+++ b/src/vs/workbench/contrib/update/electron-browser/update.ts -@@ -5,36 +5,24 @@ - - import * as nls from 'vs/nls'; - import severity from 'vs/base/common/severity'; --import { Action } from 'vs/base/common/actions'; - import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle'; --import pkg from 'vs/platform/product/node/package'; --import product from 'vs/platform/product/node/product'; --import { URI } from 'vs/base/common/uri'; - import { IActivityService, NumberBadge, IBadge, ProgressBadge } from 'vs/workbench/services/activity/common/activity'; --import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; - import { GLOBAL_ACTIVITY_ID } from 'vs/workbench/common/activity'; --import { IOpenerService } from 'vs/platform/opener/common/opener'; - import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; - import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; - import { IUpdateService, State as UpdateState, StateType, IUpdate } from 'vs/platform/update/common/update'; --import * as semver from 'semver-umd'; --import { IEnvironmentService } from 'vs/platform/environment/common/environment'; - import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; - import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; - import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; --import { ReleaseNotesManager } from './releaseNotesEditor'; --import { isWindows } from 'vs/base/common/platform'; --import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; - import { RawContextKey, IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; - import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; - import { CommandsRegistry } from 'vs/platform/commands/common/commands'; - import { FalseContext } from 'vs/platform/contextkey/common/contextkeys'; --import { ShowCurrentReleaseNotesActionId } from 'vs/workbench/contrib/update/common/update'; --import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows'; -+import { IProductService } from 'vs/platform/product/common/product'; - - const CONTEXT_UPDATE_STATE = new RawContextKey('updateState', StateType.Uninitialized); - --let releaseNotesManager: ReleaseNotesManager | undefined = undefined; -+/*let releaseNotesManager: ReleaseNotesManager | undefined = undefined; - - function showReleaseNotes(instantiationService: IInstantiationService, version: string) { - if (!releaseNotesManager) { -@@ -190,7 +178,7 @@ export class Win3264BitContribution implements IWorkbenchContribution { - } - ); - } --} -+}*/ - - export class UpdateContribution extends Disposable implements IWorkbenchContribution { - -@@ -200,13 +188,13 @@ export class UpdateContribution extends Disposable implements IWorkbenchContribu - - constructor( - @IStorageService private readonly storageService: IStorageService, -- @IInstantiationService private readonly instantiationService: IInstantiationService, - @INotificationService private readonly notificationService: INotificationService, - @IDialogService private readonly dialogService: IDialogService, - @IUpdateService private readonly updateService: IUpdateService, - @IActivityService private readonly activityService: IActivityService, - @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, -- @IContextKeyService private readonly contextKeyService: IContextKeyService -+ @IContextKeyService private readonly contextKeyService: IContextKeyService, -+ @IProductService private readonly productService: IProductService, - ) { - super(); - this.state = updateService.state; -@@ -223,7 +211,7 @@ export class UpdateContribution extends Disposable implements IWorkbenchContribu - updated since 5 days. - */ - -- const currentVersion = product.commit; -+ const currentVersion = this.productService.commit; - const lastKnownVersion = this.storageService.get('update/lastKnownVersion', StorageScope.GLOBAL); - - // if current version != stored version, clear both fields -@@ -268,9 +256,9 @@ export class UpdateContribution extends Disposable implements IWorkbenchContribu - let clazz: string | undefined; - - if (state.type === StateType.AvailableForDownload || state.type === StateType.Downloaded || state.type === StateType.Ready) { -- badge = new NumberBadge(1, () => nls.localize('updateIsReady', "New {0} update available.", product.nameShort)); -+ badge = new NumberBadge(1, () => nls.localize('updateIsReady', "New {0} update available.", this.productService.nameShort)); - } else if (state.type === StateType.CheckingForUpdates || state.type === StateType.Downloading || state.type === StateType.Updating) { -- badge = new ProgressBadge(() => nls.localize('updateIsReady', "New {0} update available.", product.nameShort)); -+ badge = new ProgressBadge(() => nls.localize('updateIsReady', "New {0} update available.", this.productService.nameShort)); - clazz = 'progress-badge'; - } - -@@ -316,14 +304,14 @@ export class UpdateContribution extends Disposable implements IWorkbenchContribu - }, { - label: nls.localize('later', "Later"), - run: () => { } -- }, { -+ }/*, { - label: nls.localize('releaseNotes', "Release Notes"), - run: () => { - const action = this.instantiationService.createInstance(ShowReleaseNotesAction, update.productVersion); - action.run(); - action.dispose(); - } -- }], -+ }*/], - { sticky: true } - ); - } -@@ -336,35 +324,32 @@ export class UpdateContribution extends Disposable implements IWorkbenchContribu - - this.notificationService.prompt( - severity.Info, -- nls.localize('updateAvailable', "There's an update available: {0} {1}", product.nameLong, update.productVersion), -+ nls.localize('updateAvailable', "There's an update available: {0} {1}", this.productService.nameLong, update.productVersion), - [{ - label: nls.localize('installUpdate', "Install Update"), - run: () => this.updateService.applyUpdate() - }, { - label: nls.localize('later', "Later"), - run: () => { } -- }, { -+ }/*, { - label: nls.localize('releaseNotes', "Release Notes"), - run: () => { - const action = this.instantiationService.createInstance(ShowReleaseNotesAction, update.productVersion); - action.run(); - action.dispose(); - } -- }], -+ }*/], - { sticky: true } - ); - } - - // windows fast updates - private onUpdateUpdating(update: IUpdate): void { -- if (isWindows && product.target === 'user') { -- return; -- } - - // windows fast updates (target === system) - this.notificationService.prompt( - severity.Info, -- nls.localize('updateInstalling', "{0} {1} is being installed in the background; we'll let you know when it's done.", product.nameLong, update.productVersion), -+ nls.localize('updateInstalling', "{0} {1} is being installed in the background; we'll let you know when it's done.", this.productService.nameLong, update.productVersion), - [], - { - neverShowAgain: { id: 'neverShowAgain:update/win32-fast-updates', isSecondary: true } -@@ -374,20 +359,17 @@ export class UpdateContribution extends Disposable implements IWorkbenchContribu - - // windows and mac - private onUpdateReady(update: IUpdate): void { -- if (!(isWindows && product.target !== 'user') && !this.shouldShowNotification()) { -- return; -- } - - const actions = [{ - label: nls.localize('updateNow', "Update Now"), -- run: () => this.updateService.quitAndInstall() -+ run: () => { this.updateService.quitAndInstall(); window.location.reload(); } - }, { - label: nls.localize('later', "Later"), - run: () => { } - }]; - - // TODO@joao check why snap updates send `update` as falsy -- if (update.productVersion) { -+ /*if (update.productVersion) { - actions.push({ - label: nls.localize('releaseNotes', "Release Notes"), - run: () => { -@@ -396,19 +378,19 @@ export class UpdateContribution extends Disposable implements IWorkbenchContribu - action.dispose(); - } - }); -- } -+ }*/ - - // windows user fast updates and mac - this.notificationService.prompt( - severity.Info, -- nls.localize('updateAvailableAfterRestart', "Restart {0} to apply the latest update.", product.nameLong), -+ nls.localize('updateAvailableAfterRestart', "Restart {0} to apply the latest update.", this.productService.nameLong), - actions, - { sticky: true } - ); - } - - private shouldShowNotification(): boolean { -- const currentVersion = product.commit; -+ const currentVersion = this.productService.commit; - const currentMillis = new Date().getTime(); - const lastKnownVersion = this.storageService.get('update/lastKnownVersion', StorageScope.GLOBAL); - -@@ -451,7 +433,7 @@ export class UpdateContribution extends Disposable implements IWorkbenchContribu - group: '5_update', - command: { - id: 'update.downloadNow', -- title: nls.localize('download update', "Download Update") -+ title: nls.localize('installUpdate', "Install Update") - }, - when: CONTEXT_UPDATE_STATE.isEqualTo(StateType.AvailableForDownload) - }); -@@ -488,7 +470,7 @@ export class UpdateContribution extends Disposable implements IWorkbenchContribu - when: CONTEXT_UPDATE_STATE.isEqualTo(StateType.Updating) - }); - -- CommandsRegistry.registerCommand('update.restart', () => this.updateService.quitAndInstall()); -+ CommandsRegistry.registerCommand('update.restart', () => { this.updateService.quitAndInstall(); window.location.reload(); }); - MenuRegistry.appendMenuItem(MenuId.GlobalActivity, { - group: '5_update', - command: { diff --git a/src/vs/workbench/contrib/webview/browser/pre/main.js b/src/vs/workbench/contrib/webview/browser/pre/main.js -index c97da43b4c..6a66b9435f 100644 +index e6b9fd854b..a3d0a46e3a 100644 --- a/src/vs/workbench/contrib/webview/browser/pre/main.js +++ b/src/vs/workbench/contrib/webview/browser/pre/main.js -@@ -411,7 +411,7 @@ +@@ -308,7 +308,8 @@ + } else { + // Rewrite vscode-resource in csp + if (data.endpoint) { +- csp.setAttribute('content', csp.getAttribute('content').replace(/vscode-resource:/g, data.endpoint)); ++ // NOTE@coder: Add back the trailing slash so it'll work for sub-paths. ++ csp.setAttribute('content', csp.getAttribute('content').replace(/vscode-resource:/g, data.endpoint + "/")); + } + } - newFrame.contentWindow.addEventListener('keydown', handleInnerKeydown); - -- newFrame.contentWindow.addEventListener('DOMContentLoaded', e => { -+ newFrame.contentWindow.addEventListener('load', e => { - if (host.fakeLoad) { - newFrame.contentDocument.open(); - newFrame.contentDocument.write(newDocument); -diff --git a/src/vs/workbench/contrib/webview/browser/webviewElement.ts b/src/vs/workbench/contrib/webview/browser/webviewElement.ts -index a7b1d1bd42..61fe0f205e 100644 ---- a/src/vs/workbench/contrib/webview/browser/webviewElement.ts -+++ b/src/vs/workbench/contrib/webview/browser/webviewElement.ts -@@ -184,7 +184,7 @@ export class IFrameWebview extends Disposable implements Webview { - - private preprocessHtml(value: string): string { - return value.replace(/(["'])vscode-resource:([^\s'"]+?)(["'])/gi, (_, startQuote, path, endQuote) => -- `${startQuote}${this.endpoint}/vscode-resource${path}${endQuote}`); -+ `${startQuote}${this.endpoint}/vscode-resource${path}${endQuote}`).replace(/vscode-resource:/g, `'self'`); - } - - public update(html: string, options: WebviewContentOptions, retainContextWhenHidden: boolean) { -diff --git a/src/vs/workbench/contrib/welcome/walkThrough/browser/editor/editorWalkThrough.ts b/src/vs/workbench/contrib/welcome/walkThrough/browser/editor/editorWalkThrough.ts -index 8493b87f2c..b5c47ea23f 100644 ---- a/src/vs/workbench/contrib/welcome/walkThrough/browser/editor/editorWalkThrough.ts -+++ b/src/vs/workbench/contrib/welcome/walkThrough/browser/editor/editorWalkThrough.ts -@@ -16,7 +16,8 @@ const typeId = 'workbench.editors.walkThroughInput'; - const inputOptions: WalkThroughInputOptions = { - typeId, - name: localize('editorWalkThrough.title', "Interactive Playground"), -- resource: URI.parse(require.toUrl('./vs_code_editor_walkthrough.md')) -+ resource: URI.parse(require.toUrl('./vs_code_editor_walkthrough.md') -+ .replace(`${window.location.origin}${window.location.pathname.replace(/\/+$/, '')}`, window.location.origin)) - .with({ scheme: Schemas.walkThrough }), - telemetryFrom: 'walkThrough' - }; diff --git a/src/vs/workbench/services/environment/browser/environmentService.ts b/src/vs/workbench/services/environment/browser/environmentService.ts -index 7c3b6ae53e..18dec6effa 100644 +index 5f221e07ff..bfd592382c 100644 --- a/src/vs/workbench/services/environment/browser/environmentService.ts +++ b/src/vs/workbench/services/environment/browser/environmentService.ts -@@ -177,6 +177,8 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment +@@ -15,7 +15,6 @@ import { IPath, IPathsToWaitFor, IWindowConfiguration } from 'vs/platform/window + import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; + import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; + import { IWorkbenchConstructionOptions } from 'vs/workbench/workbench.web.api'; +-import product from 'vs/platform/product/common/product'; + + export class BrowserWindowConfiguration implements IWindowConfiguration { + +@@ -180,12 +179,13 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment driverHandle?: string; driverVerbose: boolean; galleryMachineIdResource?: URI; @@ -1325,9 +718,17 @@ index 7c3b6ae53e..18dec6effa 100644 + extraBuiltinExtensionPaths: string[]; readonly logFile: URI; + get webviewExternalEndpoint(): string { +- // TODO: get fallback from product.json +- return (this.options.webviewEndpoint || 'https://{{uuid}}.vscode-webview-test.com/{{commit}}') +- .replace('{{commit}}', product.commit || '211fa02efe8c041fd7baa8ec3dce199d5185aa44'); ++ // NOTE@coder: Modified to work against the current URL. ++ return `${window.location.origin}${window.location.pathname.replace(/\/+$/, '')}/webview/`; + } + get webviewResourceRoot(): string { diff --git a/src/vs/workbench/services/extensions/browser/extensionService.ts b/src/vs/workbench/services/extensions/browser/extensionService.ts -index 0f09ebb5b6..1efd5fb196 100644 +index 000e5f7b4a..39f46e68a1 100644 --- a/src/vs/workbench/services/extensions/browser/extensionService.ts +++ b/src/vs/workbench/services/extensions/browser/extensionService.ts @@ -119,6 +119,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten @@ -1339,10 +740,10 @@ index 0f09ebb5b6..1efd5fb196 100644 this._checkEnableProposedApi(remoteEnv.extensions); diff --git a/src/vs/workbench/services/extensions/common/extensionsUtil.ts b/src/vs/workbench/services/extensions/common/extensionsUtil.ts -index a1496708db..e65acfffbe 100644 +index 49b2d270c0..45200ccdbb 100644 --- a/src/vs/workbench/services/extensions/common/extensionsUtil.ts +++ b/src/vs/workbench/services/extensions/common/extensionsUtil.ts -@@ -12,7 +12,7 @@ import { IProductService } from 'vs/platform/product/common/product'; +@@ -12,7 +12,7 @@ import { IProductService } from 'vs/platform/product/common/productService'; export function isWebExtension(manifest: IExtensionManifest, configurationService: IConfigurationService): boolean { const extensionKind = getExtensionKind(manifest, configurationService); @@ -1352,10 +753,10 @@ index a1496708db..e65acfffbe 100644 export function isUIExtension(manifest: IExtensionManifest, productService: IProductService, configurationService: IConfigurationService): boolean { diff --git a/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts b/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts -index 6d31b177ac..67c955a59d 100644 +index 9f5a14f6cb..ca952f3d4d 100644 --- a/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts +++ b/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts -@@ -41,12 +41,12 @@ const args = minimist(process.argv.slice(2), { +@@ -42,12 +42,13 @@ const args = minimist(process.argv.slice(2), { const Module = require.__$__nodeRequire('module') as any; const originalLoad = Module._load; @@ -1366,21 +767,27 @@ index 6d31b177ac..67c955a59d 100644 } - return originalLoad.apply(this, arguments); ++ // NOTE@coder: Map node_module.asar requests to regular node_modules. + return originalLoad.apply(this, [request.replace(/node_modules\.asar(\.unpacked)?/, 'node_modules'), parent, isMain]); }; })(); -@@ -128,7 +128,7 @@ function _createExtHostProtocol(): Promise { - } else { - // Do not wait for web companion to reconnect - protocol.onSocketClose(() => { -- onTerminate(); -+ process.send!({ type: 'VSCODE_EXTHOST_DISCONNECTED' }); - }); - } +@@ -120,8 +121,11 @@ function _createExtHostProtocol(): Promise { + + // Wait for rich client to reconnect + protocol.onSocketClose(() => { +- // The socket has closed, let's give the renderer a certain amount of time to reconnect +- disconnectRunner1.schedule(); ++ // NOTE@coder: Inform the server so we can manage offline ++ // connections there instead. Our goal is to persist connections ++ // forever (to a reasonable point) to account for things like ++ // hibernating overnight. ++ process.send!({ type: 'VSCODE_EXTHOST_DISCONNECTED' }); + }); } + } diff --git a/src/vs/workbench/services/extensions/worker/extHost.services.ts b/src/vs/workbench/services/extensions/worker/extHost.services.ts -index bf4a779155..1aa90b3e36 100644 +index 3bdfa1a79f..ded21cf9c6 100644 --- a/src/vs/workbench/services/extensions/worker/extHost.services.ts +++ b/src/vs/workbench/services/extensions/worker/extHost.services.ts @@ -21,6 +21,7 @@ import { ExtHostExtensionService } from 'vs/workbench/api/worker/extHostExtensio @@ -1399,16 +806,74 @@ index bf4a779155..1aa90b3e36 100644 // register services that only throw errors function NotImplementedProxy(name: ServiceIdentifier): { new(): T } { +diff --git a/src/vs/workbench/services/localizations/electron-browser/localizationsService.ts b/src/vs/workbench/services/localizations/electron-browser/localizationsService.ts +index 99394090da..4891e0fece 100644 +--- a/src/vs/workbench/services/localizations/electron-browser/localizationsService.ts ++++ b/src/vs/workbench/services/localizations/electron-browser/localizationsService.ts +@@ -5,17 +5,17 @@ + + import { createChannelSender } from 'vs/base/parts/ipc/node/ipc'; + import { ILocalizationsService } from 'vs/platform/localizations/common/localizations'; +-import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService'; + import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; ++import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; + + export class LocalizationsService { + + _serviceBrand: undefined; + + constructor( +- @ISharedProcessService sharedProcessService: ISharedProcessService, ++ @IRemoteAgentService remoteAgentService: IRemoteAgentService, + ) { +- return createChannelSender(sharedProcessService.getChannel('localizations')); ++ return createChannelSender(remoteAgentService.getConnection()!.getChannel('localizations')); + } + } + +diff --git a/src/vs/workbench/services/update/electron-browser/updateService.ts b/src/vs/workbench/services/update/electron-browser/updateService.ts +index b8f6558b2c..b1fe6b14fd 100644 +--- a/src/vs/workbench/services/update/electron-browser/updateService.ts ++++ b/src/vs/workbench/services/update/electron-browser/updateService.ts +@@ -6,7 +6,7 @@ + import { IChannel } from 'vs/base/parts/ipc/common/ipc'; + import { Event, Emitter } from 'vs/base/common/event'; + import { IUpdateService, State } from 'vs/platform/update/common/update'; +-import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService'; ++import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; + import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; + + export class NativeUpdateService implements IUpdateService { +@@ -21,8 +21,9 @@ export class NativeUpdateService implements IUpdateService { + + private channel: IChannel; + +- constructor(@IMainProcessService mainProcessService: IMainProcessService) { +- this.channel = mainProcessService.getChannel('update'); ++ // NOTE@coder: patched to work in the browser. ++ constructor(@IRemoteAgentService remoteAgentService: IRemoteAgentService) { ++ this.channel = remoteAgentService.getConnection()!.getChannel('update'); + + // always set this._state as the state changes + this.onStateChange(state => this._state = state); diff --git a/src/vs/workbench/workbench.web.main.ts b/src/vs/workbench/workbench.web.main.ts -index 681fc606b6..e34ef5d4bc 100644 +index fa9c9dd7a9..688d6c1934 100644 --- a/src/vs/workbench/workbench.web.main.ts +++ b/src/vs/workbench/workbench.web.main.ts -@@ -34,7 +34,7 @@ import 'vs/workbench/services/textfile/browser/textFileService'; +@@ -34,11 +34,14 @@ import 'vs/workbench/services/textfile/browser/browserTextFileService'; import 'vs/workbench/services/keybinding/browser/keymapService'; import 'vs/workbench/services/extensions/browser/extensionService'; import 'vs/workbench/services/extensionManagement/common/extensionManagementServerService'; -import 'vs/workbench/services/telemetry/browser/telemetryService'; ++// NOTE@coder: We send it all to the server side to be processed there instead. +// import 'vs/workbench/services/telemetry/browser/telemetryService'; import 'vs/workbench/services/configurationResolver/browser/configurationResolverService'; import 'vs/workbench/services/credentials/browser/credentialsService'; import 'vs/workbench/services/url/browser/urlService'; +-import 'vs/workbench/services/update/browser/updateService'; ++// NOTE@coder: Use the electron-browser version since it already comes with a ++// channel which lets us actually perform updates. ++import 'vs/workbench/services/update/electron-browser/updateService'; + import 'vs/workbench/contrib/stats/browser/workspaceStatsService'; + import 'vs/workbench/services/workspaces/browser/workspacesService'; + import 'vs/workbench/services/workspaces/browser/workspaceEditingService'; diff --git a/src/browser/api.ts b/src/browser/api.ts index 649ebd71..e6187468 100644 --- a/src/browser/api.ts +++ b/src/browser/api.ts @@ -15,7 +15,7 @@ import { IInstantiationService, ServiceIdentifier } from "vs/platform/instantiat import { ServiceCollection } from "vs/platform/instantiation/common/serviceCollection"; import { INotificationService } from "vs/platform/notification/common/notification"; import { Registry } from "vs/platform/registry/common/platform"; -import { IStatusbarEntry, IStatusbarEntryAccessor, IStatusbarService, StatusbarAlignment } from "vs/platform/statusbar/common/statusbar"; +import { IStatusbarEntry, IStatusbarEntryAccessor, IStatusbarService, StatusbarAlignment } from "vs/workbench/services/statusbar/common/statusbar"; import { IStorageService } from "vs/platform/storage/common/storage"; import { ITelemetryService } from "vs/platform/telemetry/common/telemetry"; import { IThemeService } from "vs/platform/theme/common/themeService"; diff --git a/src/browser/client.ts b/src/browser/client.ts index c83e4bac..677ea9b8 100644 --- a/src/browser/client.ts +++ b/src/browser/client.ts @@ -3,16 +3,13 @@ import { URI } from "vs/base/common/uri"; import { registerSingleton } from "vs/platform/instantiation/common/extensions"; import { ServiceCollection } from "vs/platform/instantiation/common/serviceCollection"; import { ILocalizationsService } from "vs/platform/localizations/common/localizations"; -import { LocalizationsService } from "vs/platform/localizations/electron-browser/localizationsService"; +import { LocalizationsService } from "vs/workbench/services/localizations/electron-browser/localizationsService"; import { ITelemetryService } from "vs/platform/telemetry/common/telemetry"; -import { IUpdateService } from "vs/platform/update/common/update"; -import { UpdateService } from "vs/platform/update/electron-browser/updateService"; import { coderApi, vscodeApi } from "vs/server/src/browser/api"; import { IUploadService, UploadService } from "vs/server/src/browser/upload"; import { INodeProxyService, NodeProxyChannelClient } from "vs/server/src/common/nodeProxy"; import { TelemetryChannelClient } from "vs/server/src/common/telemetry"; import "vs/workbench/contrib/localizations/browser/localizations.contribution"; -import "vs/workbench/contrib/update/electron-browser/update.contribution"; import { IRemoteAgentService } from "vs/workbench/services/remote/common/remoteAgentService"; import { PersistentConnectionEventType } from "vs/platform/remote/common/remoteAgentConnection"; @@ -52,7 +49,6 @@ class NodeProxyService extends NodeProxyChannelClient implements INodeProxyServi registerSingleton(ILocalizationsService, LocalizationsService); registerSingleton(INodeProxyService, NodeProxyService); registerSingleton(ITelemetryService, TelemetryService); -registerSingleton(IUpdateService, UpdateService); registerSingleton(IUploadService, UploadService, true); /** diff --git a/src/browser/upload.ts b/src/browser/upload.ts index 23ab914f..96f0fd09 100644 --- a/src/browser/upload.ts +++ b/src/browser/upload.ts @@ -8,8 +8,8 @@ import { IFileService } from "vs/platform/files/common/files"; import { createDecorator, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { INotificationService, Severity } from "vs/platform/notification/common/notification"; import { IProgress, IProgressService, IProgressStep, ProgressLocation } from "vs/platform/progress/common/progress"; -import { IWindowsService } from "vs/platform/windows/common/windows"; import { IWorkspaceContextService } from "vs/platform/workspace/common/workspace"; +import { IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; import { ExplorerItem } from "vs/workbench/contrib/files/common/explorerModel"; import { IEditorGroup } from "vs/workbench/services/editor/common/editorGroupsService"; import { IEditorService } from "vs/workbench/services/editor/common/editorService"; @@ -29,7 +29,7 @@ export class UploadService extends Disposable implements IUploadService { public constructor( @IInstantiationService instantiationService: IInstantiationService, @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, - @IWindowsService private readonly windowsService: IWindowsService, + @IWorkspacesService private readonly workspacesService: IWorkspacesService, @IEditorService private readonly editorService: IEditorService, ) { super(); @@ -38,10 +38,10 @@ export class UploadService extends Disposable implements IUploadService { public async handleDrop(event: DragEvent, resolveTargetGroup: () => IEditorGroup | undefined, afterDrop: (targetGroup: IEditorGroup | undefined) => void, targetIndex?: number): Promise { // TODO: should use the workspace for the editor it was dropped on? - const target =this.contextService.getWorkspace().folders[0].uri; + const target = this.contextService.getWorkspace().folders[0].uri; const uris = (await this.upload.uploadDropped(event, target)).map((u) => URI.file(u)); if (uris.length > 0) { - await this.windowsService.addRecentlyOpened(uris.map((u) => ({ fileUri: u }))); + await this.workspacesService.addRecentlyOpened(uris.map((u) => ({ fileUri: u }))); } const editors = uris.map((uri) => ({ resource: uri, diff --git a/src/browser/workbench-build.html b/src/browser/workbench-build.html new file mode 100644 index 00000000..60bba416 --- /dev/null +++ b/src/browser/workbench-build.html @@ -0,0 +1,109 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/browser/workbench.html b/src/browser/workbench.html new file mode 100644 index 00000000..940c6cd7 --- /dev/null +++ b/src/browser/workbench.html @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/node/channel.ts b/src/node/channel.ts index 05accab0..b0edd09b 100644 --- a/src/node/channel.ts +++ b/src/node/channel.ts @@ -12,8 +12,7 @@ import { ExtensionIdentifier, IExtensionDescription } from "vs/platform/extensio import { FileDeleteOptions, FileOpenOptions, FileOverwriteOptions, FileType, IStat, IWatchOptions } from "vs/platform/files/common/files"; import { DiskFileSystemProvider } from "vs/platform/files/node/diskFileSystemProvider"; import { ILogService } from "vs/platform/log/common/log"; -import pkg from "vs/platform/product/node/package"; -import product from "vs/platform/product/node/product"; +import product from "vs/platform/product/common/product"; import { IRemoteAgentEnvironment } from "vs/platform/remote/common/remoteAgentEnvironment"; import { ITelemetryService } from "vs/platform/telemetry/common/telemetry"; import { INodeProxyService } from "vs/server/src/common/nodeProxy"; @@ -228,7 +227,7 @@ export class ExtensionEnvironmentChannel implements IServerChannel { const scanMultiple = (isBuiltin: boolean, isUnderDevelopment: boolean, paths: string[]): Promise => { return Promise.all(paths.map((path) => { return ExtensionScanner.scanExtensions(new ExtensionScannerInput( - pkg.version, + product.version, product.commit, locale, !!process.env.VSCODE_DEV, @@ -295,7 +294,7 @@ export class NodeProxyService implements INodeProxyService { public readonly onClose = this._onClose.event; public constructor() { - // TODO: close/down/up + // TODO: down/up const { Server } = localRequire("@coder/node-browser/out/server/server"); this.server = new Server({ onMessage: this.$onMessage, diff --git a/src/node/cli.ts b/src/node/cli.ts index f505fe50..bd3c1da6 100644 --- a/src/node/cli.ts +++ b/src/node/cli.ts @@ -5,10 +5,9 @@ import { setUnexpectedErrorHandler } from "vs/base/common/errors"; import { main as vsCli } from "vs/code/node/cliProcessMain"; import { validatePaths } from "vs/code/node/paths"; import { ParsedArgs } from "vs/platform/environment/common/environment"; -import { buildHelpMessage, buildVersionMessage, Option as VsOption, options as vsOptions } from "vs/platform/environment/node/argv"; +import { buildHelpMessage, buildVersionMessage, Option as VsOption, OPTIONS, OptionDescriptions } from "vs/platform/environment/node/argv"; import { parseMainProcessArgv } from "vs/platform/environment/node/argvHelper"; -import pkg from "vs/platform/product/node/package"; -import product from "vs/platform/product/node/product"; +import product from "vs/platform/product/common/product"; import { ipcMain } from "vs/server/src/node/ipc"; import { enableCustomMarketplace } from "vs/server/src/node/marketplace"; import { MainServer } from "vs/server/src/node/server"; @@ -24,7 +23,7 @@ interface Args extends ParsedArgs { "cert-key"?: string; format?: string; host?: string; - open?: string; + open?: boolean; port?: string; socket?: string; } @@ -35,14 +34,9 @@ interface Option extends VsOption { } const getArgs = (): Args => { - const options = vsOptions as Option[]; - // The last item is _ which is like -- so our options need to come before it. - const last = options.pop()!; - // Remove options that won't work or don't make sense. - let i = options.length; - while (i--) { - switch (options[i].id) { + for (let key in OPTIONS) { + switch (key) { case "add": case "diff": case "file-uri": @@ -57,24 +51,21 @@ const getArgs = (): Args => { case "prof-startup": case "inspect-extensions": case "inspect-brk-extensions": - options.splice(i, 1); + delete OPTIONS[key]; break; } } - options.push({ id: "base-path", type: "string", cat: "o", description: "Base path of the URL at which code-server is hosted (used for login redirects)." }); - options.push({ id: "cert", type: "string", cat: "o", description: "Path to certificate. If the path is omitted, both this and --cert-key will be generated." }); - options.push({ id: "cert-key", type: "string", cat: "o", description: "Path to the certificate's key if one was provided." }); - options.push({ id: "extra-builtin-extensions-dir", type: "string", cat: "o", description: "Path to an extra builtin extension directory." }); - options.push({ id: "extra-extensions-dir", type: "string", cat: "o", description: "Path to an extra user extension directory." }); - options.push({ id: "format", type: "string", cat: "o", description: `Format for the version. ${buildAllowedMessage(FormatType)}.` }); - options.push({ id: "host", type: "string", cat: "o", description: "Host for the server." }); - options.push({ id: "auth", type: "string", cat: "o", description: `The type of authentication to use. ${buildAllowedMessage(AuthType)}.` }); - options.push({ id: "open", type: "boolean", cat: "o", description: "Open in the browser on startup." }); - options.push({ id: "port", type: "string", cat: "o", description: "Port for the main server." }); - options.push({ id: "socket", type: "string", cat: "o", description: "Listen on a socket instead of host:port." }); - - options.push(last); + const options = OPTIONS as OptionDescriptions>; + options["base-path"] = { type: "string", cat: "o", description: "Base path of the URL at which code-server is hosted (used for login redirects)." }; + options["cert"] = { type: "string", cat: "o", description: "Path to certificate. If the path is omitted, both this and --cert-key will be generated." }; + options["cert-key"] = { type: "string", cat: "o", description: "Path to the certificate's key if one was provided." }; + options["format"] = { type: "string", cat: "o", description: `Format for the version. ${buildAllowedMessage(FormatType)}.` }; + options["host"] = { type: "string", cat: "o", description: "Host for the server." }; + options["auth"] = { type: "string", cat: "o", description: `The type of authentication to use. ${buildAllowedMessage(AuthType)}.` }; + options["open"] = { type: "boolean", cat: "o", description: "Open in the browser on startup." }; + options["port"] = { type: "string", cat: "o", description: "Port for the main server." }; + options["socket"] = { type: "string", cat: "o", description: "Listen on a socket instead of host:port." }; const args = parseMainProcessArgv(process.argv); if (!args["user-data-dir"]) { @@ -84,6 +75,10 @@ const getArgs = (): Args => { args["extensions-dir"] = path.join(args["user-data-dir"], "extensions"); } + if (!args.verbose && !args.log && process.env.LOG_LEVEL) { + args.log = process.env.LOG_LEVEL; + } + return validatePaths(args); }; @@ -161,19 +156,19 @@ const startCli = (): boolean | Promise => { const args = getArgs(); if (args.help) { const executable = `${product.applicationName}${os.platform() === "win32" ? ".exe" : ""}`; - console.log(buildHelpMessage(product.nameLong, executable, pkg.codeServerVersion, undefined, false)); + console.log(buildHelpMessage(product.nameLong, executable, product.codeServerVersion, OPTIONS, false)); return true; } if (args.version) { if (args.format === "json") { console.log(JSON.stringify({ - codeServerVersion: pkg.codeServerVersion, + codeServerVersion: product.codeServerVersion, commit: product.commit, - vscodeVersion: pkg.version, + vscodeVersion: product.version, })); } else { - buildVersionMessage(pkg.codeServerVersion, product.commit).split("\n").map((line) => logger.info(line)); + buildVersionMessage(product.codeServerVersion, product.commit).split("\n").map((line) => logger.info(line)); } return true; } diff --git a/src/node/marketplace.ts b/src/node/marketplace.ts index 9c2abff9..1f086553 100644 --- a/src/node/marketplace.ts +++ b/src/node/marketplace.ts @@ -5,7 +5,7 @@ import { CancellationToken } from "vs/base/common/cancellation"; import { mkdirp } from "vs/base/node/pfs"; import * as vszip from "vs/base/node/zip"; import * as nls from "vs/nls"; -import product from "vs/platform/product/node/product"; +import product from "vs/platform/product/common/product"; import { localRequire } from "vs/server/src/node/util"; const tarStream = localRequire("tar-stream/index"); diff --git a/src/node/nls.ts b/src/node/nls.ts index 30922502..6f8d4e3d 100644 --- a/src/node/nls.ts +++ b/src/node/nls.ts @@ -3,7 +3,7 @@ import * as path from "path"; import * as util from "util"; import { getPathFromAmdModule } from "vs/base/common/amd"; import * as lp from "vs/base/node/languagePacks"; -import product from "vs/platform/product/node/product"; +import product from "vs/platform/product/common/product"; import { Translations } from "vs/workbench/services/extensions/common/extensionPoints"; const configurations = new Map>(); @@ -28,6 +28,12 @@ export const getNlsConfiguration = async (locale: string, userDataPath: string): if (isInternalConfiguration(config)) { config._languagePackSupport = true; } + // If the configuration has no results keep trying since code-server + // doesn't restart when a language is installed so this result would + // persist (the plugin might not be installed yet or something). + if (config.locale !== "en" && config.locale !== "en-us" && Object.keys(config.availableLanguages).length === 0) { + configurations.delete(id); + } resolve(config); })); } diff --git a/src/node/server.ts b/src/node/server.ts index 3de91258..b2467133 100644 --- a/src/node/server.ts +++ b/src/node/server.ts @@ -17,13 +17,12 @@ import { generateUuid } from "vs/base/common/uuid"; import { getMachineId } from 'vs/base/node/id'; import { NLSConfiguration } from "vs/base/node/languagePacks"; import { mkdirp, rimraf } from "vs/base/node/pfs"; -import { ClientConnectionEvent, IPCServer, StaticRouter } from "vs/base/parts/ipc/common/ipc"; +import { ClientConnectionEvent, IPCServer } from "vs/base/parts/ipc/common/ipc"; +import { createChannelReceiver } from "vs/base/parts/ipc/node/ipc"; import { LogsDataCleaner } from "vs/code/electron-browser/sharedProcess/contrib/logsDataCleaner"; import { IConfigurationService } from "vs/platform/configuration/common/configuration"; import { ConfigurationService } from "vs/platform/configuration/node/configurationService"; import { ExtensionHostDebugBroadcastChannel } from "vs/platform/debug/common/extensionHostDebugIpc"; -import { IDialogService } from "vs/platform/dialogs/common/dialogs"; -import { DialogChannelClient } from "vs/platform/dialogs/node/dialogIpc"; import { IEnvironmentService, ParsedArgs } from "vs/platform/environment/common/environment"; import { EnvironmentService } from "vs/platform/environment/node/environmentService"; import { ExtensionGalleryService } from "vs/platform/extensionManagement/common/extensionGalleryService"; @@ -38,13 +37,11 @@ import { InstantiationService } from "vs/platform/instantiation/common/instantia import { ServiceCollection } from "vs/platform/instantiation/common/serviceCollection"; import { ILocalizationsService } from "vs/platform/localizations/common/localizations"; import { LocalizationsService } from "vs/platform/localizations/node/localizations"; -import { LocalizationsChannel } from "vs/platform/localizations/node/localizationsIpc"; import { getLogLevel, ILogService } from "vs/platform/log/common/log"; -import { LogLevelSetterChannel } from "vs/platform/log/common/logIpc"; +import { LoggerChannel } from "vs/platform/log/common/logIpc"; import { SpdLogService } from "vs/platform/log/node/spdlogService"; -import { IProductService } from "vs/platform/product/common/product"; -import pkg from "vs/platform/product/node/package"; -import product from "vs/platform/product/node/product"; +import product from 'vs/platform/product/common/product'; +import { IProductService } from "vs/platform/product/common/productService"; import { ConnectionType, ConnectionTypeRequest } from "vs/platform/remote/common/remoteAgentConnection"; import { REMOTE_FILE_SYSTEM_CHANNEL_NAME } from "vs/platform/remote/common/remoteAgentFileSystemChannel"; import { IRequestService } from "vs/platform/request/common/request"; @@ -56,14 +53,14 @@ import { ITelemetryServiceConfig, TelemetryService } from "vs/platform/telemetry import { combinedAppender, LogAppender, NullTelemetryService } from "vs/platform/telemetry/common/telemetryUtils"; import { AppInsightsAppender } from "vs/platform/telemetry/node/appInsightsAppender"; import { resolveCommonProperties } from "vs/platform/telemetry/node/commonProperties"; -import { UpdateChannel } from "vs/platform/update/node/updateIpc"; +import { UpdateChannel } from "vs/platform/update/electron-main/updateIpc"; +import { INodeProxyService, NodeProxyChannel } from "vs/server/src/common/nodeProxy"; +import { TelemetryChannel } from "vs/server/src/common/telemetry"; import { ExtensionEnvironmentChannel, FileProviderChannel, NodeProxyService } from "vs/server/src/node/channel"; import { Connection, ExtensionHostConnection, ManagementConnection } from "vs/server/src/node/connection"; import { TelemetryClient } from "vs/server/src/node/insights"; import { getLocaleFromConfig, getNlsConfiguration } from "vs/server/src/node/nls"; -import { NodeProxyChannel, INodeProxyService } from "vs/server/src/common/nodeProxy"; import { Protocol } from "vs/server/src/node/protocol"; -import { TelemetryChannel } from "vs/server/src/common/telemetry"; import { UpdateService } from "vs/server/src/node/update"; import { AuthType, getMediaMime, getUriTransformer, localRequire, tmpdir } from "vs/server/src/node/util"; import { RemoteExtensionLogFileName } from "vs/workbench/services/remote/common/remoteAgentService"; @@ -82,8 +79,9 @@ export enum HttpCode { } export interface Options { - WORKBENCH_WEB_CONGIGURATION: IWorkbenchConstructionOptions; + WORKBENCH_WEB_CONFIGURATION: IWorkbenchConstructionOptions & { folderUri?: UriComponents, workspaceUri?: UriComponents }; REMOTE_USER_DATA_URI: UriComponents | URI; + PRODUCT_CONFIGURATION: Partial; NLS_CONFIGURATION: NLSConfiguration; } @@ -280,7 +278,7 @@ export abstract class Server { // without adding query parameters which have their own issues. // REVIEW: Discuss whether this is the best option; this is sort of a quick // hack almost to get caching in the meantime but it does work pretty well. - if (/^\/static-.+/.test(base)) { + if (/^\/static-/.test(base)) { base = "/static"; } @@ -361,7 +359,7 @@ export abstract class Server { if (this.authenticate(request, data)) { return { redirect: "/", - headers: {"Set-Cookie": `password=${data.password}` } + headers: { "Set-Cookie": `password=${data.password}` } }; } console.error("Failed login attempt", JSON.stringify({ @@ -538,7 +536,7 @@ export class MainServer extends Server { } private async getRoot(request: http.IncomingMessage, parsedUrl: url.UrlWithParsedQuery): Promise { - const filePath = path.join(this.rootPath, "out/vs/code/browser/workbench/workbench.html"); + const filePath = path.join(this.rootPath, "out/vs/server/src/browser/workbench.html"); let [content, startPath] = await Promise.all([ util.promisify(fs.readFile)(filePath, "utf8"), this.getFirstValidPath([ @@ -567,17 +565,20 @@ export class MainServer extends Server { const environment = this.services.get(IEnvironmentService) as IEnvironmentService; const options: Options = { - WORKBENCH_WEB_CONGIGURATION: { + WORKBENCH_WEB_CONFIGURATION: { workspaceUri: startPath && startPath.workspace ? transformer.transformOutgoing(startPath.uri) : undefined, folderUri: startPath && !startPath.workspace ? transformer.transformOutgoing(startPath.uri) : undefined, remoteAuthority, - productConfiguration: product, + logLevel: getLogLevel(environment), + }, + REMOTE_USER_DATA_URI: transformer.transformOutgoing(URI.file(environment.userDataPath)), + PRODUCT_CONFIGURATION: { + extensionsGallery: product.extensionsGallery, }, - REMOTE_USER_DATA_URI: transformer.transformOutgoing((environment).webUserDataHome), NLS_CONFIGURATION: await getNlsConfiguration(environment.args.locale || await getLocaleFromConfig(environment.userDataPath), environment.userDataPath), }; - content = content.replace(/\/static\//g, `/static${product.commit ? `-${product.commit}` : ""}/`).replace("{{WEBVIEW_ENDPOINT}}", ""); + content = content.replace(/{{COMMIT}}/g, product.commit || ""); for (const key in options) { content = content.replace(`"{{${key}}}"`, `'${JSON.stringify(options[key as keyof Options])}'`); } @@ -698,17 +699,15 @@ export class MainServer extends Server { ...environmentService.extraBuiltinExtensionPaths, ); - this.ipc.registerChannel("loglevel", new LogLevelSetterChannel(logService)); + this.ipc.registerChannel("logger", new LoggerChannel(logService)); this.ipc.registerChannel(ExtensionHostDebugBroadcastChannel.ChannelName, new ExtensionHostDebugBroadcastChannel()); - const router = new StaticRouter((ctx: any) => ctx.clientId === "renderer"); this.services.set(ILogService, logService); this.services.set(IEnvironmentService, environmentService); this.services.set(IConfigurationService, new SyncDescriptor(ConfigurationService, [environmentService.machineSettingsResource])); this.services.set(IRequestService, new SyncDescriptor(RequestService)); this.services.set(IFileService, fileService); this.services.set(IProductService, { _serviceBrand: undefined, ...product }); - this.services.set(IDialogService, new DialogChannelClient(this.ipc.getChannel("dialog", router))); this.services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryService)); this.services.set(IExtensionManagementService, new SyncDescriptor(ExtensionManagementService)); @@ -719,7 +718,7 @@ export class MainServer extends Server { new LogAppender(logService), ), commonProperties: resolveCommonProperties( - product.commit, pkg.codeServerVersion, await getMachineId(), + product.commit, product.codeServerVersion, await getMachineId(), [], environmentService.installSourcePath, "code-server", ), piiPaths: this.allowedRequestPaths, @@ -730,32 +729,25 @@ export class MainServer extends Server { await new Promise((resolve) => { const instantiationService = new InstantiationService(this.services); - const localizationService = instantiationService.createInstance(LocalizationsService); - this.services.set(ILocalizationsService, localizationService); - const proxyService = instantiationService.createInstance(NodeProxyService); - this.services.set(INodeProxyService, proxyService); - this.ipc.registerChannel("localizations", new LocalizationsChannel(localizationService)); + this.services.set(ILocalizationsService, instantiationService.createInstance(LocalizationsService)); + this.services.set(INodeProxyService, instantiationService.createInstance(NodeProxyService)); + instantiationService.invokeFunction(() => { instantiationService.createInstance(LogsDataCleaner); - - const extensionsService = this.services.get(IExtensionManagementService) as IExtensionManagementService; const telemetryService = this.services.get(ITelemetryService) as ITelemetryService; - - const extensionsChannel = new ExtensionManagementChannel(extensionsService, (context) => getUriTransformer(context.remoteAuthority)); - const extensionsEnvironmentChannel = new ExtensionEnvironmentChannel(environmentService, logService, telemetryService, this.options.connectionToken || ""); - const fileChannel = new FileProviderChannel(environmentService, logService); - const requestChannel = new RequestChannel(this.services.get(IRequestService) as IRequestService); - const telemetryChannel = new TelemetryChannel(telemetryService); - const updateChannel = new UpdateChannel(instantiationService.createInstance(UpdateService)); - const nodeProxyChannel = new NodeProxyChannel(proxyService); - - this.ipc.registerChannel("extensions", extensionsChannel); - this.ipc.registerChannel("remoteextensionsenvironment", extensionsEnvironmentChannel); - this.ipc.registerChannel("request", requestChannel); - this.ipc.registerChannel("telemetry", telemetryChannel); - this.ipc.registerChannel("nodeProxy", nodeProxyChannel); - this.ipc.registerChannel("update", updateChannel); - this.ipc.registerChannel(REMOTE_FILE_SYSTEM_CHANNEL_NAME, fileChannel); + this.ipc.registerChannel("extensions", new ExtensionManagementChannel( + this.services.get(IExtensionManagementService) as IExtensionManagementService, + (context) => getUriTransformer(context.remoteAuthority), + )); + this.ipc.registerChannel("remoteextensionsenvironment", new ExtensionEnvironmentChannel( + environmentService, logService, telemetryService, this.options.connectionToken || "", + )); + this.ipc.registerChannel("request", new RequestChannel(this.services.get(IRequestService) as IRequestService)); + this.ipc.registerChannel("telemetry", new TelemetryChannel(telemetryService)); + this.ipc.registerChannel("nodeProxy", new NodeProxyChannel(this.services.get(INodeProxyService) as INodeProxyService)); + this.ipc.registerChannel("localizations", createChannelReceiver(this.services.get(ILocalizationsService) as ILocalizationsService)); + this.ipc.registerChannel("update", new UpdateChannel(instantiationService.createInstance(UpdateService))); + this.ipc.registerChannel(REMOTE_FILE_SYSTEM_CHANNEL_NAME, new FileProviderChannel(environmentService, logService)); resolve(new ErrorTelemetry(telemetryService)); }); }); diff --git a/src/node/update.ts b/src/node/update.ts index af58d444..dcd0422b 100644 --- a/src/node/update.ts +++ b/src/node/update.ts @@ -11,9 +11,9 @@ import { IConfigurationService } from "vs/platform/configuration/common/configur import { IEnvironmentService } from "vs/platform/environment/common/environment"; import { IFileService } from "vs/platform/files/common/files"; import { ILogService } from "vs/platform/log/common/log"; -import pkg from "vs/platform/product/node/package"; +import product from "vs/platform/product/common/product"; import { asJson, IRequestService } from "vs/platform/request/common/request"; -import { AvailableForDownload, State, StateType, UpdateType } from "vs/platform/update/common/update"; +import { AvailableForDownload, State, UpdateType } from "vs/platform/update/common/update"; import { AbstractUpdateService } from "vs/platform/update/electron-main/abstractUpdateService"; import { ipcMain } from "vs/server/src/node/ipc"; import { extract } from "vs/server/src/node/marketplace"; @@ -43,25 +43,22 @@ export class UpdateService extends AbstractUpdateService { } if (latest) { const latestMajor = parseInt(latest.name); - const currentMajor = parseInt(pkg.codeServerVersion); + const currentMajor = parseInt(product.codeServerVersion); return !isNaN(latestMajor) && !isNaN(currentMajor) && - currentMajor <= latestMajor && latest.name === pkg.codeServerVersion; + currentMajor <= latestMajor && latest.name === product.codeServerVersion; } return true; } - protected buildUpdateFeedUrl(): string { - return "https://api.github.com/repos/cdr/code-server/releases/latest"; + protected buildUpdateFeedUrl(quality: string): string { + return `${product.updateUrl}/${quality}`; } - protected doQuitAndInstall(): void { + public async doQuitAndInstall(): Promise { ipcMain.relaunch(); } protected async doCheckForUpdates(context: any): Promise { - if (this.state.type !== StateType.Idle) { - return Promise.resolve(); - } this.setState(State.CheckingForUpdates(context)); try { const update = await this.getLatestVersion(); @@ -81,15 +78,13 @@ export class UpdateService extends AbstractUpdateService { private async getLatestVersion(): Promise { const data = await this.requestService.request({ url: this.url, - headers: { - "User-Agent": "code-server", - }, + headers: { "User-Agent": "code-server" }, }, CancellationToken.None); return asJson(data); } protected async doDownloadUpdate(state: AvailableForDownload): Promise { - this.setState(State.Updating(state.update)); + this.setState(State.Downloading(state.update)); const target = os.platform(); const releaseName = await this.buildReleaseName(state.update.version); const url = "https://github.com/cdr/code-server/releases/download/" @@ -125,8 +120,7 @@ export class UpdateService extends AbstractUpdateService { private onRequestError(error: Error, showNotification?: boolean): void { this.logService.error(error); - const message: string | undefined = showNotification ? (error.message || error.toString()) : undefined; - this.setState(State.Idle(UpdateType.Archive, message)); + this.setState(State.Idle(UpdateType.Archive, showNotification ? (error.message || error.toString()) : undefined)); } private async buildReleaseName(release: string): Promise { @@ -136,7 +130,7 @@ export class UpdateService extends AbstractUpdateService { stderr: error.message, stdout: "", })); - if (result.stderr.indexOf("musl") !== -1 || result.stdout.indexOf("musl") !== -1) { + if (/^musl/.test(result.stderr) || /^musl/.test(result.stdout)) { target = "alpine"; } } diff --git a/yarn.lock b/yarn.lock index 94d15d7c..f5d01be8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -18,10 +18,10 @@ node-fetch "^2.3.0" ora "^3.2.0" -"@coder/node-browser@^1.0.5": - version "1.0.5" - resolved "https://registry.yarnpkg.com/@coder/node-browser/-/node-browser-1.0.5.tgz#58275041cbe11808574260bb2f41db3965388f88" - integrity sha512-9iN6RqJCErlp30Da/PJBGf8YT9phSTCtCgoufDQqSkSMmnV+Oho4nkFKPKB3jVb9RG5lqgi7oJpNMSXPluvlyw== +"@coder/node-browser@^1.0.6": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@coder/node-browser/-/node-browser-1.0.6.tgz#8db01974322ec63b6df62b8b7b1b3b58dc4a034e" + integrity sha512-+DXWyXSiOZ6aU+V4XYa74jT+LeQE4UumWO0Mff6HAWzZmbBn3cqibmAx/qz99aBJfD3nQ1HGHf8/Ad/AgW/quw== "@coder/requirefs@^1.0.6": version "1.0.6" @@ -30,6 +30,13 @@ optionalDependencies: jszip "2.6.0" +"@types/fs-extra@^8.0.1": + version "8.0.1" + resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-8.0.1.tgz#a2378d6e7e8afea1564e44aafa2e207dadf77686" + integrity sha512-J00cVDALmi/hJOYsunyT52Hva5TnJeKP5yd1r+mH/ZU0mbYZflR0Z5kw5kITtKTRYMhm1JMClOFYdHnQszEvqw== + dependencies: + "@types/node" "*" + "@types/node@*", "@types/node@^10.12.12": version "10.14.12" resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.12.tgz#0eec3155a46e6c4db1f27c3e588a205f767d622f" @@ -116,6 +123,11 @@ are-we-there-yet@~1.1.2: delegates "^1.0.0" readable-stream "^2.0.6" +arg@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.1.tgz#485f8e7c390ce4c5f78257dbea80d4be11feda4c" + integrity sha512-SlmP3fEA88MBv0PypnXZ8ZfJhwmDeIE3SP71j37AiXQBXYosPV0x6uISAaHYSlSVhmHOVkomen0tbGk6Anlebw== + arr-diff@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" @@ -236,6 +248,11 @@ buffer-fill@^1.0.0: resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" integrity sha1-+PeLdniYiO858gXNY39o5wISKyw= +buffer-from@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" + integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== + cache-base@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" @@ -494,6 +511,11 @@ detect-libc@^1.0.2: resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= +diff@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.1.tgz#0c667cb467ebbb5cea7f14f135cc2dba7780a8ff" + integrity sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q== + dot-prop@^4.1.0: version "4.2.0" resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57" @@ -639,6 +661,15 @@ fs-extra@^7.0.1: jsonfile "^4.0.0" universalify "^0.1.0" +fs-extra@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" + integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^4.0.0" + universalify "^0.1.0" + fs-minipass@^1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d" @@ -737,7 +768,7 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.2: resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA== -graceful-fs@^4.1.6: +graceful-fs@^4.1.6, graceful-fs@^4.2.0: version "4.2.2" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.2.tgz#6f0952605d0140c1cfdb138ed005775b92d67b02" integrity sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q== @@ -1142,6 +1173,11 @@ make-dir@^1.0.0: dependencies: pify "^3.0.0" +make-error@^1.1.1: + version "1.3.5" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.5.tgz#efe4e81f6db28cadd605c70f29c831b58ef776c8" + integrity sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g== + map-cache@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" @@ -1792,6 +1828,14 @@ source-map-resolve@^0.5.0: source-map-url "^0.4.0" urix "^0.1.0" +source-map-support@^0.5.6: + version "0.5.13" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" + integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + source-map-url@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" @@ -1802,6 +1846,11 @@ source-map@^0.5.6: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= +source-map@^0.6.0: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + split-string@^3.0.1, split-string@^3.0.2: version "3.1.0" resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" @@ -1980,6 +2029,17 @@ touch@^3.1.0: dependencies: nopt "~1.0.10" +ts-node@^8.4.1: + version "8.4.1" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.4.1.tgz#270b0dba16e8723c9fa4f9b4775d3810fd994b4f" + integrity sha512-5LpRN+mTiCs7lI5EtbXmF/HfMeCjzt7DH9CZwtkr6SywStrNQC723wG+aOWFiLNn7zT3kD/RnFqi3ZUfr4l5Qw== + dependencies: + arg "^4.1.0" + diff "^4.0.1" + make-error "^1.1.1" + source-map-support "^0.5.6" + yn "^3.0.0" + undefsafe@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.2.tgz#225f6b9e0337663e0d8e7cfd686fc2836ccace76" @@ -2132,3 +2192,8 @@ yallist@^3.0.0, yallist@^3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9" integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A== + +yn@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" + integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==