Archived
1
0

Update VS Code to 1.37.0

This commit is contained in:
Asher 2019-08-09 18:50:05 -05:00
parent b257c60636
commit ba7285192c
No known key found for this signature in database
GPG Key ID: D63C1EF81242354A
21 changed files with 644 additions and 1589 deletions

View File

@ -8,14 +8,14 @@ matrix:
- os: linux - os: linux
dist: trusty dist: trusty
env: env:
- VSCODE_VERSION="1.36.1" MAJOR_VERSION="2" VERSION="$MAJOR_VERSION.$TRAVIS_BUILD_NUMBER" TARGET="linux" - VSCODE_VERSION="1.37.0" MAJOR_VERSION="2" VERSION="$MAJOR_VERSION.$TRAVIS_BUILD_NUMBER" TARGET="linux"
- os: linux - os: linux
dist: trusty dist: trusty
env: env:
- VSCODE_VERSION="1.36.1" MAJOR_VERSION="2" VERSION="$MAJOR_VERSION.$TRAVIS_BUILD_NUMBER" TARGET="alpine" - VSCODE_VERSION="1.37.0" MAJOR_VERSION="2" VERSION="$MAJOR_VERSION.$TRAVIS_BUILD_NUMBER" TARGET="alpine"
- os: osx - os: osx
env: env:
- VSCODE_VERSION="1.36.1" MAJOR_VERSION="2" VERSION="$MAJOR_VERSION.$TRAVIS_BUILD_NUMBER" - VSCODE_VERSION="1.37.0" MAJOR_VERSION="2" VERSION="$MAJOR_VERSION.$TRAVIS_BUILD_NUMBER"
before_install: before_install:
- if [[ "$TRAVIS_BRANCH" == "master" ]]; then export MINIFY="true"; fi - if [[ "$TRAVIS_BRANCH" == "master" ]]; then export MINIFY="true"; fi
script: script:

View File

@ -81,7 +81,7 @@ data collected to improve code-server.
```shell ```shell
git clone https://github.com/microsoft/vscode git clone https://github.com/microsoft/vscode
cd vscode cd vscode
git checkout 1.36.1 git checkout 1.37.0
git clone https://github.com/cdr/code-server src/vs/server git clone https://github.com/cdr/code-server src/vs/server
cd src/vs/server cd src/vs/server
yarn patch:apply yarn patch:apply
@ -109,23 +109,19 @@ directory.
Our changes include: Our changes include:
- Add a `code-server` schema. - Add a `code-server` schema.
- Make the extension sidebar work in the browser. Mostly involves removing
Node-specific code for the `extensions` channel client and adding a
`gallery` channel.
- Allow multiple extension directories (both user and built-in). - Allow multiple extension directories (both user and built-in).
- Rewrite assets used in the CSS (like icons) or as images to use the base URL. - Rewrite assets requested by the browser to use the base URL.
- Change the loader to use the base URL. - Modify the loader to use the base URL.
- Change the web socket to use the base URL and TLS if necessary. - Modify the web socket to use the base URL and TLS if necessary.
- Set the favicon using a relative path. - Send client-side telemetry through the server.
- Modify the file service to support writing from an asynchronous stream (for
uploading files).
- Add a file prefix to ignore for temporary files created during upload. - Add a file prefix to ignore for temporary files created during upload.
- Insert our upload service for use in editor windows and explorer. - Insert our upload service for use in editor windows and explorer.
- Modify the log level to get its initial setting from the server. - Modify the log level to get its initial setting from the server.
- Get telemetry working by adding a channel for it.
- Change a regular expression used for mnemonics so it works on Firefox. - Change a regular expression used for mnemonics so it works on Firefox.
- Make it possible for us to load code on the client. - Make it possible for us to load code on the client.
- Modify the build process to include our code. - Modify the build process to include our code.
- Fix a CSP issue within a webview.
- Fix an issue displaying extension contributions.
## License ## License
[MIT](LICENSE) [MIT](LICENSE)

58
scripts/build-json.js Normal file
View File

@ -0,0 +1,58 @@
// 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/cli.js",
"vs/server/src/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();

View File

@ -1,23 +0,0 @@
// This is used to merge JSON files (package.json and product.json) and delete a
// few entries we don't want. It's extremely simple, expects very specific
// input, and doesn't have any error handling.
const fs = require("fs");
const a = process.argv[2];
const b = process.argv[3];
const out = process.argv[4];
const json = JSON.parse(process.argv[5] || "{}");
const aJson = JSON.parse(fs.readFileSync(a));
const bJson = JSON.parse(fs.readFileSync(b));
delete aJson.scripts;
delete aJson.dependencies;
delete aJson.devDependencies;
delete aJson.optionalDependencies;
fs.writeFileSync(out, JSON.stringify({
...aJson,
...bJson,
...json,
}, null, 2));

View File

@ -56,9 +56,9 @@ function prepend-loader() {
# Copy code-server into VS Code then build it. # Copy code-server into VS Code then build it.
function build-code-server() { function build-code-server() {
copy-server copy-server
yarn gulp compile-build --max-old-space-size=32384
local min="" local min=""
export BUILD_SOURCEVERSION
BUILD_SOURCEVERSION=$(node -p "require('${sourcePath}/build/lib/git.js').getVersion('${rootPath}')")
if [[ -n "${minify}" ]] ; then if [[ -n "${minify}" ]] ; then
min="-min" min="-min"
yarn gulp minify-vscode --max-old-space-size=32384 yarn gulp minify-vscode --max-old-space-size=32384
@ -74,11 +74,9 @@ function build-code-server() {
cd "${buildPath}" && yarn --production --force --build-from-source cd "${buildPath}" && yarn --production --force --build-from-source
rm "${buildPath}/"{package.json,yarn.lock,.yarnrc} rm "${buildPath}/"{package.json,yarn.lock,.yarnrc}
local packageJson="{\"codeServerVersion\": \"${codeServerVersion}-vsc${vscodeVersion}\"}"
cp -r "${sourcePath}/.build/extensions" "${buildPath}" cp -r "${sourcePath}/.build/extensions" "${buildPath}"
node "${rootPath}/scripts/merge.js" "${sourcePath}/package.json" "${rootPath}/scripts/package.json" "${buildPath}/package.json" "${packageJson}"
node "${rootPath}/scripts/merge.js" "${sourcePath}/.build/product.json" "${rootPath}/scripts/product.json" "${buildPath}/product.json"
cp -r "${sourcePath}/out-vscode${min}" "${buildPath}/out" 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. # Only keep production dependencies for the server.
cp "${rootPath}/"{package.json,yarn.lock} "${buildPath}/out/vs/server" cp "${rootPath}/"{package.json,yarn.lock} "${buildPath}/out/vs/server"
@ -143,7 +141,7 @@ function build-task() {
log "Pre-built VS Code ${vscodeVersion} has no built extensions" "error" log "Pre-built VS Code ${vscodeVersion} has no built extensions" "error"
exit 1 exit 1
fi fi
yarn gulp extensions-build-package --max-old-space-size=32384 yarn gulp compile-extensions-build --max-old-space-size=32384
fi fi
build-code-server build-code-server
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,35 +1,34 @@
import * as vscode from "vscode"; import { createCSSRule } from "vs/base/browser/dom";
import { Emitter, Event } from "vs/base/common/event";
import { IDisposable } from "vs/base/common/lifecycle";
import { URI } from "vs/base/common/uri";
import { generateUuid } from "vs/base/common/uuid";
import { localize } from "vs/nls"; import { localize } from "vs/nls";
import { SyncActionDescriptor } from "vs/platform/actions/common/actions"; import { SyncActionDescriptor } from "vs/platform/actions/common/actions";
import { Registry } from "vs/platform/registry/common/platform";
import { IWorkbenchActionRegistry, Extensions as ActionExtensions} from "vs/workbench/common/actions";
import { CommandsRegistry, ICommandService } from "vs/platform/commands/common/commands"; import { CommandsRegistry, ICommandService } from "vs/platform/commands/common/commands";
import { IStat, IWatchOptions, FileOverwriteOptions, FileDeleteOptions, FileOpenOptions, IFileChange, FileWriteOptions, FileSystemProviderCapabilities, IFileService, FileType, IFileSystemProvider } from "vs/platform/files/common/files"; import { IConfigurationService } from "vs/platform/configuration/common/configuration";
import { IStorageService } from "vs/platform/storage/common/storage"; import { IContextMenuService } from "vs/platform/contextview/browser/contextView";
import { FileDeleteOptions, FileOpenOptions, FileOverwriteOptions, FileSystemProviderCapabilities, FileType, FileWriteOptions, IFileChange, IFileService, IFileSystemProvider, IStat, IWatchOptions } from "vs/platform/files/common/files";
import { IInstantiationService, ServiceIdentifier } from "vs/platform/instantiation/common/instantiation";
import { ServiceCollection } from "vs/platform/instantiation/common/serviceCollection"; import { ServiceCollection } from "vs/platform/instantiation/common/serviceCollection";
import { INotificationService } from "vs/platform/notification/common/notification"; import { INotificationService } from "vs/platform/notification/common/notification";
import { Emitter, Event } from "vs/base/common/event"; import { Registry } from "vs/platform/registry/common/platform";
import * as extHostTypes from "vs/workbench/api/common/extHostTypes"; import { IStorageService } from "vs/platform/storage/common/storage";
import { ServiceIdentifier, IInstantiationService } from "vs/platform/instantiation/common/instantiation";
import { URI } from "vs/base/common/uri";
import { ITreeItem, ITreeViewDataProvider, IViewsRegistry, ITreeViewDescriptor, Extensions as ViewsExtensions, IViewContainersRegistry, TreeItemCollapsibleState } from "vs/workbench/common/views";
import { CustomTreeViewPanel, CustomTreeView } from "vs/workbench/browser/parts/views/customView";
import { ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor, ShowViewletAction } from "vs/workbench/browser/viewlet";
import { IExtensionService } from "vs/workbench/services/extensions/common/extensions";
import { ViewContainerViewlet } from "vs/workbench/browser/parts/views/viewsViewlet";
import { IConfigurationService } from "vs/platform/configuration/common/configuration";
import { IWorkbenchLayoutService } from "vs/workbench/services/layout/browser/layoutService";
import { ITelemetryService } from "vs/platform/telemetry/common/telemetry"; import { ITelemetryService } from "vs/platform/telemetry/common/telemetry";
import { IWorkspaceContextService } from "vs/platform/workspace/common/workspace";
import { IEditorService } from "vs/workbench/services/editor/common/editorService";
import { IThemeService } from "vs/platform/theme/common/themeService"; import { IThemeService } from "vs/platform/theme/common/themeService";
import { IContextMenuService } from "vs/platform/contextview/browser/contextView"; import { IWorkspaceContextService } from "vs/platform/workspace/common/workspace";
import { IViewletService } from "vs/workbench/services/viewlet/browser/viewlet"; import * as extHostTypes from "vs/workbench/api/common/extHostTypes";
import { CustomTreeView, CustomTreeViewPanel } from "vs/workbench/browser/parts/views/customView";
import { ViewContainerViewlet } from "vs/workbench/browser/parts/views/viewsViewlet";
import { Extensions as ViewletExtensions, ShowViewletAction, ViewletDescriptor, ViewletRegistry } from "vs/workbench/browser/viewlet";
import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from "vs/workbench/common/actions";
import { Extensions as ViewsExtensions, ITreeItem, ITreeViewDataProvider, ITreeViewDescriptor, IViewContainersRegistry, IViewsRegistry, TreeItemCollapsibleState } from "vs/workbench/common/views";
import { IEditorGroupsService } from "vs/workbench/services/editor/common/editorGroupsService"; import { IEditorGroupsService } from "vs/workbench/services/editor/common/editorGroupsService";
import { createCSSRule } from "vs/base/browser/dom"; import { IEditorService } from "vs/workbench/services/editor/common/editorService";
import { IDisposable } from "vs/base/common/lifecycle"; import { IExtensionService } from "vs/workbench/services/extensions/common/extensions";
import { generateUuid } from "vs/base/common/uuid"; import { IWorkbenchLayoutService } from "vs/workbench/services/layout/browser/layoutService";
import { IViewletService } from "vs/workbench/services/viewlet/browser/viewlet";
import * as vscode from "vscode";
/** /**
* Client-side implementation of VS Code's API. * Client-side implementation of VS Code's API.

View File

@ -1,5 +1,4 @@
import * as path from "path"; import * as path from "path";
import { VSBuffer } from "vs/base/common/buffer"; import { VSBuffer } from "vs/base/common/buffer";
import { Emitter, Event } from "vs/base/common/event"; import { Emitter, Event } from "vs/base/common/event";
import { IDisposable } from "vs/base/common/lifecycle"; import { IDisposable } from "vs/base/common/lifecycle";
@ -9,18 +8,17 @@ import { transformOutgoingURIs } from "vs/base/common/uriIpc";
import { IServerChannel } from "vs/base/parts/ipc/common/ipc"; import { IServerChannel } from "vs/base/parts/ipc/common/ipc";
import { IDiagnosticInfo } from "vs/platform/diagnostics/common/diagnosticsService"; import { IDiagnosticInfo } from "vs/platform/diagnostics/common/diagnosticsService";
import { IEnvironmentService } from "vs/platform/environment/common/environment"; import { IEnvironmentService } from "vs/platform/environment/common/environment";
import { IExtensionDescription, ExtensionIdentifier } from "vs/platform/extensions/common/extensions"; import { ExtensionIdentifier, IExtensionDescription } from "vs/platform/extensions/common/extensions";
import { FileDeleteOptions, FileOverwriteOptions, FileType, IStat, IWatchOptions, FileOpenOptions } from "vs/platform/files/common/files"; 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 { ILogService } from "vs/platform/log/common/log";
import pkg from "vs/platform/product/node/package"; import pkg from "vs/platform/product/node/package";
import product from "vs/platform/product/node/product"; import product from "vs/platform/product/node/product";
import { IRemoteAgentEnvironment } from "vs/platform/remote/common/remoteAgentEnvironment"; import { IRemoteAgentEnvironment } from "vs/platform/remote/common/remoteAgentEnvironment";
import { ITelemetryService } from "vs/platform/telemetry/common/telemetry"; import { ITelemetryService } from "vs/platform/telemetry/common/telemetry";
import { ExtensionScanner, ExtensionScannerInput } from "vs/workbench/services/extensions/node/extensionPoints";
import { DiskFileSystemProvider } from "vs/workbench/services/files/node/diskFileSystemProvider";
import { getTranslations } from "vs/server/src/nls"; import { getTranslations } from "vs/server/src/nls";
import { getUriTransformer } from "vs/server/src/util"; import { getUriTransformer } from "vs/server/src/util";
import { ExtensionScanner, ExtensionScannerInput } from "vs/workbench/services/extensions/node/extensionPoints";
/** /**
* Extend the file provider to allow unwatching. * Extend the file provider to allow unwatching.
@ -205,7 +203,7 @@ export class ExtensionEnvironmentChannel implements IServerChannel {
appSettingsHome: this.environment.appSettingsHome, appSettingsHome: this.environment.appSettingsHome,
settingsPath: this.environment.machineSettingsHome, settingsPath: this.environment.machineSettingsHome,
logsPath: URI.file(this.environment.logsPath), logsPath: URI.file(this.environment.logsPath),
extensionsPath: URI.file(this.environment.extensionsPath), extensionsPath: URI.file(this.environment.extensionsPath!),
extensionHostLogsPath: URI.file(path.join(this.environment.logsPath, "extension-host")), extensionHostLogsPath: URI.file(path.join(this.environment.logsPath, "extension-host")),
globalStorageHome: URI.file(this.environment.globalStorageHome), globalStorageHome: URI.file(this.environment.globalStorageHome),
userHome: URI.file(this.environment.userHome), userHome: URI.file(this.environment.userHome),
@ -237,7 +235,7 @@ export class ExtensionEnvironmentChannel implements IServerChannel {
}; };
const scanInstalled = async (): Promise<IExtensionDescription[][]> => { const scanInstalled = async (): Promise<IExtensionDescription[][]> => {
return scanMultiple(false, true, [this.environment.extensionsPath, ...this.environment.extraExtensionPaths]); return scanMultiple(false, true, [this.environment.extensionsPath!, ...this.environment.extraExtensionPaths]);
}; };
return Promise.all([scanBuiltin(), scanInstalled()]).then((allExtensions) => { return Promise.all([scanBuiltin(), scanInstalled()]).then((allExtensions) => {

View File

@ -1,27 +1,16 @@
import * as cp from "child_process"; import * as cp from "child_process";
import * as os from "os"; import * as os from "os";
import { main as vsCli } from "vs/code/node/cliProcessMain"; import { main as vsCli } from "vs/code/node/cliProcessMain";
import { validatePaths } from "vs/code/node/paths"; import { validatePaths } from "vs/code/node/paths";
import { parseMainProcessArgv } from "vs/platform/environment/node/argvHelper";
import { buildHelpMessage, buildVersionMessage, options } from "vs/platform/environment/node/argv";
import { ParsedArgs } from "vs/platform/environment/common/environment"; import { ParsedArgs } from "vs/platform/environment/common/environment";
import { buildHelpMessage, buildVersionMessage, Option as VsOption, options as vsOptions } from "vs/platform/environment/node/argv";
import { parseMainProcessArgv } from "vs/platform/environment/node/argvHelper";
import pkg from "vs/platform/product/node/package"; import pkg from "vs/platform/product/node/package";
import product from "vs/platform/product/node/product"; import product from "vs/platform/product/node/product";
import { ipcMain } from "vs/server/src/ipc"; import { ipcMain } from "vs/server/src/ipc";
import { enableCustomMarketplace } from "vs/server/src/marketplace";
product.extensionsGallery = {
serviceUrl: process.env.SERVICE_URL || "https://v1.extapi.coder.com",
itemUrl: process.env.ITEM_URL || "",
controlUrl: "",
recommendationsUrl: "",
...(product.extensionsGallery || {}),
};
import { MainServer } from "vs/server/src/server"; import { MainServer } from "vs/server/src/server";
import { enableExtensionTars } from "vs/server/src/tar"; import { AuthType, buildAllowedMessage, enumToArray, generateCertificate, generatePassword, localRequire, open, unpackExecutables } from "vs/server/src/util";
import { AuthType, buildAllowedMessage, generateCertificate, generatePassword, localRequire, open, unpackExecutables } from "vs/server/src/util";
const { logger } = localRequire<typeof import("@coder/logger/out/index")>("@coder/logger/out/index"); const { logger } = localRequire<typeof import("@coder/logger/out/index")>("@coder/logger/out/index");
@ -30,15 +19,19 @@ interface Args extends ParsedArgs {
"base-path"?: string; "base-path"?: string;
cert?: string; cert?: string;
"cert-key"?: string; "cert-key"?: string;
"extra-builtin-extensions-dir"?: string;
"extra-extensions-dir"?: string;
host?: string; host?: string;
open?: string; open?: string;
port?: string; port?: string;
socket?: string; socket?: string;
} }
// @ts-ignore: Force `keyof Args` to work.
interface Option extends VsOption {
id: keyof Args;
}
const getArgs = (): Args => { const getArgs = (): Args => {
const options = vsOptions as Option[];
// The last item is _ which is like -- so our options need to come before it. // The last item is _ which is like -- so our options need to come before it.
const last = options.pop()!; const last = options.pop()!;
@ -78,13 +71,7 @@ const getArgs = (): Args => {
options.push(last); options.push(last);
const args = validatePaths(parseMainProcessArgv(process.argv)) as Args; return validatePaths(parseMainProcessArgv(process.argv));
["extra-extensions-dir", "extra-builtin-extensions-dir"].forEach((key) => {
if (typeof args[key] === "string") {
args[key] = [args[key]];
}
});
return args;
}; };
const startVscode = async (): Promise<void | void[]> => { const startVscode = async (): Promise<void | void[]> => {
@ -100,7 +87,7 @@ const startVscode = async (): Promise<void | void[]> => {
password: process.env.PASSWORD, password: process.env.PASSWORD,
}; };
if (options.auth && Object.keys(AuthType).filter((k) => AuthType[k] === options.auth).length === 0) { if (options.auth && enumToArray(AuthType).filter((t) => t === options.auth).length === 0) {
throw new Error(`'${options.auth}' is not a valid authentication type.`); throw new Error(`'${options.auth}' is not a valid authentication type.`);
} else if (options.auth && !options.password) { } else if (options.auth && !options.password) {
options.password = await generatePassword(); options.password = await generatePassword();
@ -116,7 +103,7 @@ const startVscode = async (): Promise<void | void[]> => {
options.certKey = certKey; options.certKey = certKey;
} }
enableExtensionTars(); enableCustomMarketplace();
const server = new MainServer({ const server = new MainServer({
...options, ...options,
@ -180,7 +167,7 @@ const startCli = (): boolean | Promise<void> => {
}; };
if (shouldSpawnCliProcess()) { if (shouldSpawnCliProcess()) {
enableExtensionTars(); enableCustomMarketplace();
return vsCli(args); return vsCli(args);
} }

View File

@ -1,8 +1,29 @@
import { registerSingleton } from "vs/platform/instantiation/common/extensions";
import { ServiceCollection } from "vs/platform/instantiation/common/serviceCollection"; import { ServiceCollection } from "vs/platform/instantiation/common/serviceCollection";
import { ITelemetryService } from "vs/platform/telemetry/common/telemetry";
import { ILocalizationsService } from "vs/platform/localizations/common/localizations";
import { LocalizationsService } from "vs/platform/localizations/electron-browser/localizationsService";
import { IUpdateService } from "vs/platform/update/common/update";
import { UpdateService } from "vs/platform/update/electron-browser/updateService";
import { TelemetryChannelClient } from "vs/server/src/telemetry";
import { IRemoteAgentService } from "vs/workbench/services/remote/common/remoteAgentService";
import { coderApi, vscodeApi } from "vs/server/src/api"; class TelemetryService extends TelemetryChannelClient {
public constructor(
@IRemoteAgentService remoteAgentService: IRemoteAgentService,
) {
super(remoteAgentService.getConnection()!.getChannel("telemetry"));
}
}
registerSingleton(ILocalizationsService, LocalizationsService);
registerSingleton(IUpdateService, UpdateService);
registerSingleton(ITelemetryService, TelemetryService);
import "vs/workbench/contrib/update/electron-browser/update.contribution";
import "vs/css!./media/firefox"; import "vs/css!./media/firefox";
import { coderApi, vscodeApi } from "vs/server/src/api";
/** /**
* This is called by vs/workbench/browser/web.main.ts after the workbench has * This is called by vs/workbench/browser/web.main.ts after the workbench has
@ -13,7 +34,7 @@ export const initialize = async (services: ServiceCollection): Promise<void> =>
target.ide = coderApi(services); target.ide = coderApi(services);
target.vscode = vscodeApi(services); target.vscode = vscodeApi(services);
const event = new CustomEvent('ide-ready'); const event = new CustomEvent("ide-ready");
(event as any).ide = target.ide; (event as any).ide = target.ide;
(event as any).vscode = target.vscode; (event as any).vscode = target.vscode;
window.dispatchEvent(event); window.dispatchEvent(event);

View File

@ -1,5 +1,4 @@
import * as cp from "child_process"; import * as cp from "child_process";
import { getPathFromAmdModule } from "vs/base/common/amd"; import { getPathFromAmdModule } from "vs/base/common/amd";
import { VSBuffer } from "vs/base/common/buffer"; import { VSBuffer } from "vs/base/common/buffer";
import { Emitter } from "vs/base/common/event"; import { Emitter } from "vs/base/common/event";
@ -7,11 +6,10 @@ import { ISocket } from "vs/base/parts/ipc/common/ipc.net";
import { NodeSocket } from "vs/base/parts/ipc/node/ipc.net"; import { NodeSocket } from "vs/base/parts/ipc/node/ipc.net";
import { IEnvironmentService } from "vs/platform/environment/common/environment"; import { IEnvironmentService } from "vs/platform/environment/common/environment";
import { ILogService } from "vs/platform/log/common/log"; import { ILogService } from "vs/platform/log/common/log";
import { IExtHostReadyMessage } from "vs/workbench/services/extensions/common/extensionHostProtocol";
import { getNlsConfiguration } from "vs/server/src/nls"; import { getNlsConfiguration } from "vs/server/src/nls";
import { Protocol } from "vs/server/src/protocol"; import { Protocol } from "vs/server/src/protocol";
import { uriTransformerPath } from "vs/server/src/util"; import { uriTransformerPath } from "vs/server/src/util";
import { IExtHostReadyMessage } from "vs/workbench/services/extensions/common/extensionHostProtocol";
export abstract class Connection { export abstract class Connection {
protected readonly _onClose = new Emitter<void>(); protected readonly _onClose = new Emitter<void>();
@ -126,8 +124,8 @@ export class ExtensionHostConnection extends Connection {
proc.stderr.setEncoding("utf8").on("data", (d) => this.log.error("Extension host stderr", d)); proc.stderr.setEncoding("utf8").on("data", (d) => this.log.error("Extension host stderr", d));
proc.on("message", (event) => { proc.on("message", (event) => {
if (event && event.type === "__$console") { if (event && event.type === "__$console") {
const severity = this.log[event.severity] ? event.severity : "info"; const severity = (<any>this.log)[event.severity] ? event.severity : "info";
this.log[severity]("Extension host", event.arguments); (<any>this.log)[severity]("Extension host", event.arguments);
} }
}); });

View File

@ -1,8 +1,7 @@
import * as appInsights from "applicationinsights";
import * as https from "https"; import * as https from "https";
import * as os from "os"; import * as os from "os";
import * as appInsights from "applicationinsights";
export class TelemetryClient implements appInsights.TelemetryClient { export class TelemetryClient implements appInsights.TelemetryClient {
public config: any = {}; public config: any = {};

View File

@ -1,5 +1,4 @@
import * as cp from "child_process"; import * as cp from "child_process";
import { Emitter } from "vs/base/common/event"; import { Emitter } from "vs/base/common/event";
enum ControlMessage { enum ControlMessage {

View File

@ -2,11 +2,11 @@ import * as fs from "fs";
import * as path from "path"; import * as path from "path";
import * as tarStream from "tar-stream"; import * as tarStream from "tar-stream";
import * as util from "util"; import * as util from "util";
import * as nls from "vs/nls";
import * as vszip from "vs/base/node/zip";
import { CancellationToken } from "vs/base/common/cancellation"; import { CancellationToken } from "vs/base/common/cancellation";
import { mkdirp } from "vs/base/node/pfs"; 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";
// We will be overriding these, so keep a reference to the original. // We will be overriding these, so keep a reference to the original.
const vszipExtract = vszip.extract; const vszipExtract = vszip.extract;
@ -154,10 +154,18 @@ const extractTar = async (tarPath: string, targetPath: string, options: IExtract
}; };
/** /**
* Override original functionality so we can use extensions that are in a tar in * Override original functionality so we can use a custom marketplace with
* addition to zips. * either tars or zips.
*/ */
export const enableExtensionTars = (): void => { export const enableCustomMarketplace = (): void => {
(<any>product).extensionsGallery = { // Use `any` to override readonly.
serviceUrl: process.env.SERVICE_URL || "https://v1.extapi.coder.com",
itemUrl: process.env.ITEM_URL || "",
controlUrl: "",
recommendationsUrl: "",
...(product.extensionsGallery || {}),
};
const target = vszip as typeof vszip; const target = vszip as typeof vszip;
target.zip = tar; target.zip = tar;
target.extract = extract; target.extract = extract;

View File

@ -1,7 +1,6 @@
import * as path from "path";
import * as fs from "fs"; import * as fs from "fs";
import * as path from "path";
import * as util from "util"; import * as util from "util";
import { getPathFromAmdModule } from "vs/base/common/amd"; import { getPathFromAmdModule } from "vs/base/common/amd";
import * as lp from "vs/base/node/languagePacks"; import * as lp from "vs/base/node/languagePacks";
import product from "vs/platform/product/node/product"; import product from "vs/platform/product/node/product";

View File

@ -1,8 +1,7 @@
import * as net from "net"; import * as net from "net";
import { VSBuffer } from "vs/base/common/buffer"; import { VSBuffer } from "vs/base/common/buffer";
import { NodeSocket, WebSocketNodeSocket } from "vs/base/parts/ipc/node/ipc.net";
import { PersistentProtocol } from "vs/base/parts/ipc/common/ipc.net"; import { PersistentProtocol } from "vs/base/parts/ipc/common/ipc.net";
import { NodeSocket, WebSocketNodeSocket } from "vs/base/parts/ipc/node/ipc.net";
import { AuthRequest, ConnectionTypeRequest, HandshakeMessage } from "vs/platform/remote/common/remoteAgentConnection"; import { AuthRequest, ConnectionTypeRequest, HandshakeMessage } from "vs/platform/remote/common/remoteAgentConnection";
export interface SocketOptions { export interface SocketOptions {

View File

@ -4,31 +4,34 @@ import * as http from "http";
import * as https from "https"; import * as https from "https";
import * as net from "net"; import * as net from "net";
import * as path from "path"; import * as path from "path";
import * as tls from "tls";
import * as util from "util";
import * as url from "url";
import * as querystring from "querystring"; import * as querystring from "querystring";
import * as tls from "tls";
import * as url from "url";
import * as util from "util";
import { Emitter } from "vs/base/common/event"; import { Emitter } from "vs/base/common/event";
import { sanitizeFilePath } from "vs/base/common/extpath"; import { sanitizeFilePath } from "vs/base/common/extpath";
import { UriComponents, URI } from "vs/base/common/uri"; import { Schemas } from "vs/base/common/network";
import { URI, UriComponents } from "vs/base/common/uri";
import { generateUuid } from "vs/base/common/uuid"; import { generateUuid } from "vs/base/common/uuid";
import { getMachineId } from 'vs/base/node/id'; import { getMachineId } from 'vs/base/node/id';
import { NLSConfiguration } from "vs/base/node/languagePacks"; import { NLSConfiguration } from "vs/base/node/languagePacks";
import { mkdirp, rimraf } from "vs/base/node/pfs"; import { mkdirp, rimraf } from "vs/base/node/pfs";
import { IPCServer, ClientConnectionEvent, StaticRouter } from "vs/base/parts/ipc/common/ipc"; import { ClientConnectionEvent, IPCServer, StaticRouter } from "vs/base/parts/ipc/common/ipc";
import { LogsDataCleaner } from "vs/code/electron-browser/sharedProcess/contrib/logsDataCleaner"; import { LogsDataCleaner } from "vs/code/electron-browser/sharedProcess/contrib/logsDataCleaner";
import { IConfigurationService } from "vs/platform/configuration/common/configuration"; import { IConfigurationService } from "vs/platform/configuration/common/configuration";
import { ConfigurationService } from "vs/platform/configuration/node/configurationService"; 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 { IDialogService } from "vs/platform/dialogs/common/dialogs";
import { DialogChannelClient } from "vs/platform/dialogs/node/dialogIpc"; import { DialogChannelClient } from "vs/platform/dialogs/node/dialogIpc";
import { IEnvironmentService, ParsedArgs } from "vs/platform/environment/common/environment"; import { IEnvironmentService, ParsedArgs } from "vs/platform/environment/common/environment";
import { EnvironmentService } from "vs/platform/environment/node/environmentService"; import { EnvironmentService } from "vs/platform/environment/node/environmentService";
import { IExtensionManagementService, IExtensionGalleryService } from "vs/platform/extensionManagement/common/extensionManagement"; import { ExtensionGalleryService } from "vs/platform/extensionManagement/common/extensionGalleryService";
import { ExtensionGalleryChannel } from "vs/platform/extensionManagement/node/extensionGalleryIpc"; import { IExtensionGalleryService, IExtensionManagementService } from "vs/platform/extensionManagement/common/extensionManagement";
import { ExtensionGalleryService } from "vs/platform/extensionManagement/node/extensionGalleryService"; import { ExtensionManagementChannel } from "vs/platform/extensionManagement/common/extensionManagementIpc";
import { ExtensionManagementChannel } from "vs/platform/extensionManagement/node/extensionManagementIpc";
import { ExtensionManagementService } from "vs/platform/extensionManagement/node/extensionManagementService"; import { ExtensionManagementService } from "vs/platform/extensionManagement/node/extensionManagementService";
import { IFileService } from "vs/platform/files/common/files";
import { FileService } from "vs/platform/files/common/fileService";
import { DiskFileSystemProvider } from "vs/platform/files/node/diskFileSystemProvider";
import { SyncDescriptor } from "vs/platform/instantiation/common/descriptors"; import { SyncDescriptor } from "vs/platform/instantiation/common/descriptors";
import { InstantiationService } from "vs/platform/instantiation/common/instantiationService"; import { InstantiationService } from "vs/platform/instantiation/common/instantiationService";
import { ServiceCollection } from "vs/platform/instantiation/common/serviceCollection"; import { ServiceCollection } from "vs/platform/instantiation/common/serviceCollection";
@ -38,31 +41,32 @@ import { LocalizationsChannel } from "vs/platform/localizations/node/localizatio
import { getLogLevel, ILogService } from "vs/platform/log/common/log"; import { getLogLevel, ILogService } from "vs/platform/log/common/log";
import { LogLevelSetterChannel } from "vs/platform/log/common/logIpc"; import { LogLevelSetterChannel } from "vs/platform/log/common/logIpc";
import { SpdLogService } from "vs/platform/log/node/spdlogService"; import { SpdLogService } from "vs/platform/log/node/spdlogService";
import { IProductConfiguration } from "vs/platform/product/common/product"; import { IProductConfiguration, IProductService } from "vs/platform/product/common/product";
import pkg from "vs/platform/product/node/package"; import pkg from "vs/platform/product/node/package";
import product from "vs/platform/product/node/product"; import product from "vs/platform/product/node/product";
import { ProductService } from "vs/platform/product/node/productService";
import { ConnectionType, ConnectionTypeRequest } from "vs/platform/remote/common/remoteAgentConnection"; import { ConnectionType, ConnectionTypeRequest } from "vs/platform/remote/common/remoteAgentConnection";
import { REMOTE_FILE_SYSTEM_CHANNEL_NAME } from "vs/platform/remote/common/remoteAgentFileSystemChannel"; import { REMOTE_FILE_SYSTEM_CHANNEL_NAME } from "vs/platform/remote/common/remoteAgentFileSystemChannel";
import { IRequestService } from "vs/platform/request/node/request"; import { IRequestService } from "vs/platform/request/common/request";
import { RequestChannel } from "vs/platform/request/common/requestIpc";
import { RequestService } from "vs/platform/request/node/requestService"; import { RequestService } from "vs/platform/request/node/requestService";
import ErrorTelemetry from "vs/platform/telemetry/browser/errorTelemetry"; import ErrorTelemetry from "vs/platform/telemetry/browser/errorTelemetry";
import { ITelemetryService } from "vs/platform/telemetry/common/telemetry"; import { ITelemetryService } from "vs/platform/telemetry/common/telemetry";
import { NullTelemetryService, LogAppender, combinedAppender } from "vs/platform/telemetry/common/telemetryUtils"; import { ITelemetryServiceConfig, TelemetryService } from "vs/platform/telemetry/common/telemetryService";
import { TelemetryService, ITelemetryServiceConfig } from "vs/platform/telemetry/common/telemetryService"; import { combinedAppender, LogAppender, NullTelemetryService } from "vs/platform/telemetry/common/telemetryUtils";
import { AppInsightsAppender } from "vs/platform/telemetry/node/appInsightsAppender"; import { AppInsightsAppender } from "vs/platform/telemetry/node/appInsightsAppender";
import { resolveCommonProperties } from "vs/platform/telemetry/node/commonProperties"; import { resolveCommonProperties } from "vs/platform/telemetry/node/commonProperties";
import { RemoteExtensionLogFileName } from "vs/workbench/services/remote/common/remoteAgentService";
import { TelemetryChannel } from "vs/platform/telemetry/node/telemetryIpc";
import { UpdateChannel } from "vs/platform/update/node/updateIpc"; import { UpdateChannel } from "vs/platform/update/node/updateIpc";
import { IWorkbenchConstructionOptions } from "vs/workbench/workbench.web.api"; import { ExtensionEnvironmentChannel, FileProviderChannel } from "vs/server/src/channel";
import { Connection, ExtensionHostConnection, ManagementConnection } from "vs/server/src/connection";
import { Connection, ManagementConnection, ExtensionHostConnection } from "vs/server/src/connection";
import { ExtensionEnvironmentChannel, FileProviderChannel , } from "vs/server/src/channel";
import { TelemetryClient } from "vs/server/src/insights"; import { TelemetryClient } from "vs/server/src/insights";
import { getNlsConfiguration, getLocaleFromConfig } from "vs/server/src/nls"; import { getLocaleFromConfig, getNlsConfiguration } from "vs/server/src/nls";
import { Protocol } from "vs/server/src/protocol"; import { Protocol } from "vs/server/src/protocol";
import { TelemetryChannel } from "vs/server/src/telemetry";
import { UpdateService } from "vs/server/src/update"; import { UpdateService } from "vs/server/src/update";
import { AuthType, getMediaMime, getUriTransformer, localRequire, tmpdir } from "vs/server/src/util"; import { AuthType, getMediaMime, getUriTransformer, localRequire, tmpdir } from "vs/server/src/util";
import { RemoteExtensionLogFileName } from "vs/workbench/services/remote/common/remoteAgentService";
import { IWorkbenchConstructionOptions } from "vs/workbench/workbench.web.api";
export enum HttpCode { export enum HttpCode {
Ok = 200, Ok = 200,
@ -192,9 +196,9 @@ export abstract class Server {
try { try {
const payload = await this.preHandleRequest(request); const payload = await this.preHandleRequest(request);
response.writeHead(payload.redirect ? HttpCode.Redirect : payload.code || HttpCode.Ok, { response.writeHead(payload.redirect ? HttpCode.Redirect : payload.code || HttpCode.Ok, {
"Cache-Control": "max-age=86400", // TODO: ETag?
"Content-Type": getMediaMime(payload.filePath), "Content-Type": getMediaMime(payload.filePath),
...(payload.redirect ? { Location: this.withBase(request, payload.redirect) } : {}), ...(payload.redirect ? { Location: this.withBase(request, payload.redirect) } : {}),
...(request.headers["service-worker"] ? { "Service-Worker-Allowed": this.options.basePath + "/" } : {}),
...payload.headers, ...payload.headers,
}); });
response.end(payload.content); response.end(payload.content);
@ -438,7 +442,7 @@ export class MainServer extends Server {
): Promise<Response> { ): Promise<Response> {
switch (base) { switch (base) {
case "/": return this.getRoot(request, parsedUrl); case "/": return this.getRoot(request, parsedUrl);
case "/resources": return this.getResource(requestPath); case "/vscode-resources": return this.getResource(requestPath);
case "/webview": case "/webview":
if (requestPath.indexOf("/vscode-resource") === 0) { if (requestPath.indexOf("/vscode-resource") === 0) {
return this.getResource(requestPath.replace(/^\/vscode-resource/, "")); return this.getResource(requestPath.replace(/^\/vscode-resource/, ""));
@ -490,15 +494,19 @@ export class MainServer extends Server {
NLS_CONFIGURATION: await getNlsConfiguration(locale, environment.userDataPath), NLS_CONFIGURATION: await getNlsConfiguration(locale, environment.userDataPath),
}; };
Object.keys(options).forEach((key) => { for (const key in options) {
content = content.replace(`"{{${key}}}"`, `'${JSON.stringify(options[key])}'`); content = content.replace(`"{{${key}}}"`, `'${JSON.stringify(options[key as keyof Options])}'`);
}); }
content = content.replace('{{WEBVIEW_ENDPOINT}}', webviewEndpoint); content = content.replace('{{WEBVIEW_ENDPOINT}}', webviewEndpoint);
return { content, filePath }; return { content, filePath };
} }
private async connect(message: ConnectionTypeRequest, protocol: Protocol): Promise<void> { private async connect(message: ConnectionTypeRequest, protocol: Protocol): Promise<void> {
if (product.commit && message.commit !== product.commit) {
throw new Error(`Version mismatch (${message.commit} instead of ${product.commit})`);
}
switch (message.desiredConnectionType) { switch (message.desiredConnectionType) {
case ConnectionType.ExtensionHost: case ConnectionType.ExtensionHost:
case ConnectionType.Management: case ConnectionType.Management:
@ -552,16 +560,25 @@ export class MainServer extends Server {
} }
private async initializeServices(args: ParsedArgs): Promise<void> { private async initializeServices(args: ParsedArgs): Promise<void> {
const router = new StaticRouter((ctx: any) => ctx.clientId === "renderer");
const environmentService = new EnvironmentService(args, process.execPath); const environmentService = new EnvironmentService(args, process.execPath);
const logService = new SpdLogService(RemoteExtensionLogFileName, environmentService.logsPath, getLogLevel(environmentService)); const logService = new SpdLogService(RemoteExtensionLogFileName, environmentService.logsPath, getLogLevel(environmentService));
this.ipc.registerChannel("loglevel", new LogLevelSetterChannel(logService)); const fileService = new FileService(logService);
fileService.registerProvider(Schemas.file, new DiskFileSystemProvider(logService));
this.ipc.registerChannel("loglevel", new LogLevelSetterChannel(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(ILogService, logService);
this.services.set(IEnvironmentService, environmentService); this.services.set(IEnvironmentService, environmentService);
this.services.set(IConfigurationService, new SyncDescriptor(ConfigurationService, [environmentService.machineSettingsResource])); this.services.set(IConfigurationService, new SyncDescriptor(ConfigurationService, [environmentService.machineSettingsResource]));
this.services.set(IRequestService, new SyncDescriptor(RequestService)); this.services.set(IRequestService, new SyncDescriptor(RequestService));
this.services.set(IFileService, fileService);
this.services.set(IProductService, new SyncDescriptor(ProductService));
this.services.set(IDialogService, new DialogChannelClient(this.ipc.getChannel("dialog", router)));
this.services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryService)); this.services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryService));
this.services.set(IExtensionManagementService, new SyncDescriptor(ExtensionManagementService));
if (!environmentService.args["disable-telemetry"]) { if (!environmentService.args["disable-telemetry"]) {
this.services.set(ITelemetryService, new SyncDescriptor(TelemetryService, [{ this.services.set(ITelemetryService, new SyncDescriptor(TelemetryService, [{
appender: combinedAppender( appender: combinedAppender(
@ -582,8 +599,6 @@ export class MainServer extends Server {
} else { } else {
this.services.set(ITelemetryService, NullTelemetryService); this.services.set(ITelemetryService, NullTelemetryService);
} }
this.services.set(IDialogService, new DialogChannelClient(this.ipc.getChannel("dialog", router)));
this.services.set(IExtensionManagementService, new SyncDescriptor(ExtensionManagementService));
await new Promise((resolve) => { await new Promise((resolve) => {
const instantiationService = new InstantiationService(this.services); const instantiationService = new InstantiationService(this.services);
@ -592,19 +607,23 @@ export class MainServer extends Server {
this.ipc.registerChannel("localizations", new LocalizationsChannel(localizationService)); this.ipc.registerChannel("localizations", new LocalizationsChannel(localizationService));
instantiationService.invokeFunction(() => { instantiationService.invokeFunction(() => {
instantiationService.createInstance(LogsDataCleaner); instantiationService.createInstance(LogsDataCleaner);
this.ipc.registerChannel(REMOTE_FILE_SYSTEM_CHANNEL_NAME, new FileProviderChannel(environmentService, logService));
const telemetryService = this.services.get(ITelemetryService) as ITelemetryService;
this.ipc.registerChannel("remoteextensionsenvironment", new ExtensionEnvironmentChannel(environmentService, logService, telemetryService));
const extensionsService = this.services.get(IExtensionManagementService) as IExtensionManagementService; 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 extensionsChannel = new ExtensionManagementChannel(extensionsService, (context) => getUriTransformer(context.remoteAuthority));
this.ipc.registerChannel("extensions", extensionsChannel); const extensionsEnvironmentChannel = new ExtensionEnvironmentChannel(environmentService, logService, telemetryService);
const galleryService = this.services.get(IExtensionGalleryService) as IExtensionGalleryService; const fileChannel = new FileProviderChannel(environmentService, logService);
const galleryChannel = new ExtensionGalleryChannel(galleryService); const requestChannel = new RequestChannel(this.services.get(IRequestService) as IRequestService);
this.ipc.registerChannel("gallery", galleryChannel);
const telemetryChannel = new TelemetryChannel(telemetryService); const telemetryChannel = new TelemetryChannel(telemetryService);
this.ipc.registerChannel("telemetry", telemetryChannel);
const updateChannel = new UpdateChannel(instantiationService.createInstance(UpdateService)); const updateChannel = new UpdateChannel(instantiationService.createInstance(UpdateService));
this.ipc.registerChannel("extensions", extensionsChannel);
this.ipc.registerChannel("remoteextensionsenvironment", extensionsEnvironmentChannel);
this.ipc.registerChannel("request", requestChannel);
this.ipc.registerChannel("telemetry", telemetryChannel);
this.ipc.registerChannel("update", updateChannel); this.ipc.registerChannel("update", updateChannel);
this.ipc.registerChannel(REMOTE_FILE_SYSTEM_CHANNEL_NAME, fileChannel);
resolve(new ErrorTelemetry(telemetryService)); resolve(new ErrorTelemetry(telemetryService));
}); });
}); });

49
src/telemetry.ts Normal file
View File

@ -0,0 +1,49 @@
import { ITelemetryData } from "vs/base/common/actions";
import { Event } from "vs/base/common/event";
import { IChannel, IServerChannel } from "vs/base/parts/ipc/common/ipc";
import { ClassifiedEvent, GDPRClassification, StrictPropertyCheck } from "vs/platform/telemetry/common/gdprTypings";
import { ITelemetryInfo, ITelemetryService } from "vs/platform/telemetry/common/telemetry";
export class TelemetryChannel implements IServerChannel {
constructor(private service: ITelemetryService) {}
listen(_: unknown, event: string): Event<any> {
throw new Error(`Invalid listen ${event}`);
}
call(_: unknown, command: string, args?: any): Promise<any> {
switch (command) {
case "publicLog": return this.service.publicLog(args[0], args[1], args[2]);
case "publicLog2": return this.service.publicLog2(args[0], args[1], args[2]);
case "setEnabled": return Promise.resolve(this.service.setEnabled(args[0]));
case "getTelemetryInfo": return this.service.getTelemetryInfo();
}
throw new Error(`Invalid call ${command}`);
}
}
export class TelemetryChannelClient implements ITelemetryService {
_serviceBrand: any;
constructor(private readonly channel: IChannel) {}
public publicLog(eventName: string, data?: ITelemetryData, anonymizeFilePaths?: boolean): Promise<void> {
return this.channel.call("publicLog", [eventName, data, anonymizeFilePaths]);
}
public publicLog2<E extends ClassifiedEvent<T> = never, T extends GDPRClassification<T> = never>(eventName: string, data?: StrictPropertyCheck<T, E>, anonymizeFilePaths?: boolean): Promise<void> {
return this.channel.call("publicLog2", [eventName, data, anonymizeFilePaths]);
}
public setEnabled(value: boolean): void {
this.channel.call("setEnable", [value]);
}
public getTelemetryInfo(): Promise<ITelemetryInfo> {
return this.channel.call("getTelemetryInfo");
}
public get isOptedIn(): boolean {
return true;
}
}

View File

@ -1,23 +1,24 @@
import * as cp from "child_process"; import * as cp from "child_process";
import * as os from "os"; import * as os from "os";
import * as path from "path"; import * as path from "path";
import { Stream } from "stream";
import * as util from "util"; import * as util from "util";
import * as zlib from 'zlib'; import { toVSBufferReadableStream } from "vs/base/common/buffer";
import { CancellationToken } from "vs/base/common/cancellation"; import { CancellationToken } from "vs/base/common/cancellation";
import { URI } from "vs/base/common/uri";
import * as pfs from "vs/base/node/pfs"; import * as pfs from "vs/base/node/pfs";
import { asJson, download } from "vs/base/node/request";
import { IConfigurationService } from "vs/platform/configuration/common/configuration"; import { IConfigurationService } from "vs/platform/configuration/common/configuration";
import { IEnvironmentService } from "vs/platform/environment/common/environment"; 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 { ILogService } from "vs/platform/log/common/log";
import pkg from "vs/platform/product/node/package"; import pkg from "vs/platform/product/node/package";
import { IRequestService } from "vs/platform/request/node/request"; import { asJson, IRequestService } from "vs/platform/request/common/request";
import { State, UpdateType, StateType, AvailableForDownload } from "vs/platform/update/common/update"; import { AvailableForDownload, State, StateType, UpdateType } from "vs/platform/update/common/update";
import { AbstractUpdateService } from "vs/platform/update/electron-main/abstractUpdateService"; import { AbstractUpdateService } from "vs/platform/update/electron-main/abstractUpdateService";
import { ipcMain } from "vs/server/src/ipc"; import { ipcMain } from "vs/server/src/ipc";
import { extract } from "vs/server/src/marketplace";
import { tmpdir } from "vs/server/src/util"; import { tmpdir } from "vs/server/src/util";
import { extract } from "vs/server/src/tar"; import * as zlib from "zlib";
interface IUpdate { interface IUpdate {
name: string; name: string;
@ -30,7 +31,8 @@ export class UpdateService extends AbstractUpdateService {
@IConfigurationService configurationService: IConfigurationService, @IConfigurationService configurationService: IConfigurationService,
@IEnvironmentService environmentService: IEnvironmentService, @IEnvironmentService environmentService: IEnvironmentService,
@IRequestService requestService: IRequestService, @IRequestService requestService: IRequestService,
@ILogService logService: ILogService @ILogService logService: ILogService,
@IFileService private readonly fileService: IFileService,
) { ) {
super(null, configurationService, environmentService, requestService, logService); super(null, configurationService, environmentService, requestService, logService);
} }
@ -92,10 +94,13 @@ export class UpdateService extends AbstractUpdateService {
const context = await this.requestService.request({ url }, CancellationToken.None); const context = await this.requestService.request({ url }, CancellationToken.None);
// Decompress the gzip as we download. If the gzip encoding is set then // Decompress the gzip as we download. If the gzip encoding is set then
// the request service already does this. // the request service already does this.
// HACK: This uses knowledge of the internals of the request service.
if (target !== "darwin" && context.res.headers["content-encoding"] !== "gzip") { if (target !== "darwin" && context.res.headers["content-encoding"] !== "gzip") {
context.stream = context.stream.pipe(zlib.createGunzip()); const stream = (context.res as any as Stream);
stream.removeAllListeners();
context.stream = toVSBufferReadableStream(stream.pipe(zlib.createGunzip()));
} }
await download(downloadPath, context); await this.fileService.writeFile(URI.file(downloadPath), context.stream);
await extract(downloadPath, extractPath, undefined, CancellationToken.None); await extract(downloadPath, extractPath, undefined, CancellationToken.None);
const newBinary = path.join(extractPath, releaseName, "code-server"); const newBinary = path.join(extractPath, releaseName, "code-server");
if (!pfs.exists(newBinary)) { if (!pfs.exists(newBinary)) {

View File

@ -1,18 +1,17 @@
import { generateUuid } from "vs/base/common/uuid";
import { DesktopDragAndDropData } from "vs/base/browser/ui/list/listView"; import { DesktopDragAndDropData } from "vs/base/browser/ui/list/listView";
import { VSBuffer, VSBufferReadable } from "vs/base/common/buffer"; import { VSBuffer, VSBufferReadableStream } from "vs/base/common/buffer";
import { Emitter, Event } from "vs/base/common/event";
import { Disposable } from "vs/base/common/lifecycle"; import { Disposable } from "vs/base/common/lifecycle";
import * as path from "vs/base/common/path"; import * as path from "vs/base/common/path";
import { URI } from "vs/base/common/uri"; import { URI } from "vs/base/common/uri";
import { generateUuid } from "vs/base/common/uuid";
import { IFileService } from "vs/platform/files/common/files"; import { IFileService } from "vs/platform/files/common/files";
import { createDecorator, ServiceIdentifier, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { createDecorator, IInstantiationService, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
import { INotificationService, Severity } from "vs/platform/notification/common/notification"; import { INotificationService, Severity } from "vs/platform/notification/common/notification";
import { IProgress, IProgressStep, IProgressService, ProgressLocation } from "vs/platform/progress/common/progress"; 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 { ExplorerItem } from "vs/workbench/contrib/files/common/explorerModel"; import { ExplorerItem } from "vs/workbench/contrib/files/common/explorerModel";
import { IEditorGroup } from "vs/workbench/services/editor/common/editorGroupsService"; import { IEditorGroup } from "vs/workbench/services/editor/common/editorGroupsService";
import { IWorkspaceContextService } from "vs/platform/workspace/common/workspace";
import { IWindowsService } from "vs/platform/windows/common/windows";
import { IEditorService } from "vs/workbench/services/editor/common/editorService"; import { IEditorService } from "vs/workbench/services/editor/common/editorService";
export const IUploadService = createDecorator<IUploadService>("uploadService"); export const IUploadService = createDecorator<IUploadService>("uploadService");
@ -208,20 +207,15 @@ class Upload {
), ),
}); });
const reader = new Reader(file); const reader = new Reader(file);
reader.onData((data) => { reader.on("data", (data) => {
if (data && data.length > 0) { if (data && data.byteLength > 0) {
this.uploaded += data.byteLength; this.uploaded += data.byteLength;
} }
}); });
reader.onAbort(() => {
const remaining = file.size - reader.offset;
if (remaining > 0) {
this.uploaded += remaining;
}
});
this.uploadingFiles.set(filePath, reader); this.uploadingFiles.set(filePath, reader);
await this.fileService.writeFile(tempUri, reader); await this.fileService.writeFile(tempUri, reader);
if (reader.aborted) { if (reader.aborted) {
this.uploaded += (file.size - reader.offset);
await this.fileService.del(tempUri); await this.fileService.del(tempUri);
} else { } else {
await this.fileService.move(tempUri, uri, true); await this.fileService.move(tempUri, uri, true);
@ -292,17 +286,14 @@ class Upload {
} }
} }
class Reader implements VSBufferReadable { class Reader implements VSBufferReadableStream {
private _offset = 0; private _offset = 0;
private readonly size = 32000; // ~32kb max while reading in the file. private readonly size = 32000; // ~32kb max while reading in the file.
private readonly _onData = new Emitter<Uint8Array | null>();
public readonly onData: Event<Uint8Array | null> = this._onData.event;
private _aborted = false; private _aborted = false;
private readonly _onAbort = new Emitter<void>();
public readonly onAbort: Event<void> = this._onAbort.event;
private readonly reader = new FileReader(); private readonly reader = new FileReader();
private paused = true;
private buffer?: VSBuffer;
private callbacks = new Map<string, Array<(...args: any[]) => void>>();
public constructor(private readonly file: File) { public constructor(private readonly file: File) {
this.reader.addEventListener("load", this.onLoad); this.reader.addEventListener("load", this.onLoad);
@ -311,35 +302,71 @@ class Reader implements VSBufferReadable {
public get offset(): number { return this._offset; } public get offset(): number { return this._offset; }
public get aborted(): boolean { return this._aborted; } public get aborted(): boolean { return this._aborted; }
public on(event: "data" | "error" | "end", callback: (...args:any[]) => void): void {
if (!this.callbacks.has(event)) {
this.callbacks.set(event, []);
}
this.callbacks.get(event)!.push(callback);
if (this.aborted) {
return this.emit("error", new Error("stream has been aborted"));
} else if (this.done) {
return this.emit("error", new Error("stream has ended"));
} else if (event === "end") { // Once this is being listened to we can safely start outputting data.
this.resume();
}
}
public abort = (): void => { public abort = (): void => {
this._aborted = true; this._aborted = true;
this.reader.abort(); this.reader.abort();
this.reader.removeEventListener("load", this.onLoad); this.reader.removeEventListener("load", this.onLoad);
this._onAbort.fire(); this.emit("end");
} }
public read = async (): Promise<VSBuffer | null> => { public pause(): void {
return new Promise<VSBuffer | null>((resolve) => { this.paused = true;
const disposables = [
this.onAbort(() => {
disposables.forEach((d) => d.dispose());
resolve(null);
}),
this.onData((data) => {
disposables.forEach((d) => d.dispose());
resolve(data && VSBuffer.wrap(data));
}),
];
if (this.aborted || this.offset >= this.file.size) {
return this._onData.fire(null);
}
const slice = this.file.slice(this.offset, this.offset + this.size);
this._offset += this.size;
this.reader.readAsArrayBuffer(slice);
});
} }
private onLoad = () => { public resume(): void {
this._onData.fire(new Uint8Array(this.reader.result as ArrayBuffer)); if (this.paused) {
this.paused = false;
this.readNextChunk();
}
}
public destroy(): void {
this.abort();
}
private onLoad = (): void => {
this.buffer = VSBuffer.wrap(new Uint8Array(this.reader.result as ArrayBuffer));
if (!this.paused) {
this.readNextChunk();
}
}
private readNextChunk(): void {
if (this.buffer) {
this._offset += this.buffer.byteLength;
this.emit("data", this.buffer);
this.buffer = undefined;
}
if (!this.paused) { // Could be paused during the data event.
if (this.done) {
this.emit("end");
} else {
this.reader.readAsArrayBuffer(this.file.slice(this.offset, this.offset + this.size));
}
}
}
private emit(event: "data" | "error" | "end", ...args: any[]): void {
if (this.callbacks.has(event)) {
this.callbacks.get(event)!.forEach((cb) => cb(...args));
}
}
private get done(): boolean {
return this.offset >= this.file.size;
} }
} }

View File

@ -63,12 +63,12 @@ export const generatePassword = async (length: number = 24): Promise<string> =>
}; };
export const getMediaMime = (filePath?: string): string => { export const getMediaMime = (filePath?: string): string => {
return filePath && (vsGetMediaMime(filePath) || { return filePath && (vsGetMediaMime(filePath) || (<{[index: string]: string}>{
".css": "text/css", ".css": "text/css",
".html": "text/html", ".html": "text/html",
".js": "text/javascript", ".js": "text/javascript",
".json": "application/json", ".json": "application/json",
}[extname(filePath)]) || "text/plain"; })[extname(filePath)]) || "text/plain";
}; };
export const isWsl = async (): Promise<boolean> => { export const isWsl = async (): Promise<boolean> => {
@ -113,8 +113,16 @@ export const unpackExecutables = async (): Promise<void> => {
} }
}; };
export const buildAllowedMessage = (t: typeof AuthType): string => { export const enumToArray = (t: any): string[] => {
const values = <string[]>Object.keys(t).map((k) => t[k]); const values = <string[]>[];
for (const k in t) {
values.push(t[k]);
}
return values;
};
export const buildAllowedMessage = (t: any): string => {
const values = enumToArray(t);
return `Allowed value${values.length === 1 ? " is" : "s are"} ${values.map((t) => `'${t}'`).join(",")}`; return `Allowed value${values.length === 1 ? " is" : "s are"} ${values.map((t) => `'${t}'`).join(",")}`;
}; };