fixup: move openHelpAbout

This commit is contained in:
Joe Previte 2021-03-16 14:43:29 -07:00
parent d3df963d39
commit 36714da613
No known key found for this signature in database
GPG Key ID: 2C91590C6B742C24
6 changed files with 307 additions and 281 deletions

View File

@ -2,36 +2,35 @@
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --> <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
# FAQ # FAQ
- [FAQ](#faq) - [Questions?](#questions)
- [Questions?](#questions) - [iPad Status?](#ipad-status)
- [iPad Status?](#ipad-status) - [Community Projects (awesome-code-server)](#community-projects-awesome-code-server)
- [Community Projects (awesome-code-server)](#community-projects-awesome-code-server) - [How can I reuse my VS Code configuration?](#how-can-i-reuse-my-vs-code-configuration)
- [How can I reuse my VS Code configuration?](#how-can-i-reuse-my-vs-code-configuration) - [Differences compared to VS Code?](#differences-compared-to-vs-code)
- [Differences compared to VS Code?](#differences-compared-to-vs-code) - [How can I request a missing extension?](#how-can-i-request-a-missing-extension)
- [How can I request a missing extension?](#how-can-i-request-a-missing-extension) - [How do I configure the marketplace URL?](#how-do-i-configure-the-marketplace-url)
- [How do I configure the marketplace URL?](#how-do-i-configure-the-marketplace-url) - [Where are extensions stored?](#where-are-extensions-stored)
- [Where are extensions stored?](#where-are-extensions-stored) - [How is this different from VS Code Codespaces?](#how-is-this-different-from-vs-code-codespaces)
- [How is this different from VS Code Codespaces?](#how-is-this-different-from-vs-code-codespaces) - [How should I expose code-server to the internet?](#how-should-i-expose-code-server-to-the-internet)
- [How should I expose code-server to the internet?](#how-should-i-expose-code-server-to-the-internet) - [Can I store my password hashed?](#can-i-store-my-password-hashed)
- [Can I store my password hashed?](#can-i-store-my-password-hashed) - [How do I securely access web services?](#how-do-i-securely-access-web-services)
- [How do I securely access web services?](#how-do-i-securely-access-web-services) - [Sub-paths](#sub-paths)
- [Sub-paths](#sub-paths) - [Sub-domains](#sub-domains)
- [Sub-domains](#sub-domains) - [Why does the code-server proxy strip `/proxy/<port>` from the request path?](#why-does-the-code-server-proxy-strip-proxyport-from-the-request-path)
- [Why does the code-server proxy strip `/proxy/<port>` from the request path?](#why-does-the-code-server-proxy-strip-proxyport-from-the-request-path) - [Proxying to Create React App](#proxying-to-create-react-app)
- [Proxying to Create React App](#proxying-to-create-react-app) - [Multi-tenancy](#multi-tenancy)
- [Multi-tenancy](#multi-tenancy) - [Docker in code-server container?](#docker-in-code-server-container)
- [Docker in code-server container?](#docker-in-code-server-container) - [How can I disable telemetry?](#how-can-i-disable-telemetry)
- [How can I disable telemetry?](#how-can-i-disable-telemetry) - [How does code-server decide what workspace or folder to open?](#how-does-code-server-decide-what-workspace-or-folder-to-open)
- [How does code-server decide what workspace or folder to open?](#how-does-code-server-decide-what-workspace-or-folder-to-open) - [How do I debug issues with code-server?](#how-do-i-debug-issues-with-code-server)
- [How do I debug issues with code-server?](#how-do-i-debug-issues-with-code-server) - [Heartbeat File](#heartbeat-file)
- [Heartbeat File](#heartbeat-file) - [Healthz endpoint](#healthz-endpoint)
- [Healthz endpoint](#healthz-endpoint) - [How does the config file work?](#how-does-the-config-file-work)
- [How does the config file work?](#how-does-the-config-file-work) - [Isn't an install script piped into sh insecure?](#isnt-an-install-script-piped-into-sh-insecure)
- [Isn't an install script piped into sh insecure?](#isnt-an-install-script-piped-into-sh-insecure) - [How do I make my keyboard shortcuts work?](#how-do-i-make-my-keyboard-shortcuts-work)
- [How do I make my keyboard shortcuts work?](#how-do-i-make-my-keyboard-shortcuts-work) - [Differences compared to Theia?](#differences-compared-to-theia)
- [Differences compared to Theia?](#differences-compared-to-theia) - [`$HTTP_PROXY`, `$HTTPS_PROXY`, `$NO_PROXY`](#http_proxy-https_proxy-no_proxy)
- [`$HTTP_PROXY`, `$HTTPS_PROXY`, `$NO_PROXY`](#http_proxy-https_proxy-no_proxy) - [Enterprise](#enterprise)
- [Enterprise](#enterprise)
<!-- END doctoc generated TOC please keep comment here to allow auto update --> <!-- END doctoc generated TOC please keep comment here to allow auto update -->

View File

@ -330,11 +330,7 @@ export class ExtensionEnvironmentChannel implements IServerChannel {
} }
} }
/* // Reference: - ../../workbench/api/common/extHostDebugService.ts
NOTE@coder:
Reference: - ../../workbench/api/common/extHostDebugService.ts
3/16/21 jsjoeio
*/
class VariableResolverService extends AbstractVariableResolverService { class VariableResolverService extends AbstractVariableResolverService {
constructor( constructor(
remoteAuthority: string, remoteAuthority: string,
@ -356,10 +352,6 @@ class VariableResolverService extends AbstractVariableResolverService {
return args.resolvedVariables[`config:${section}`]; return args.resolvedVariables[`config:${section}`];
}, },
getAppRoot: (): string | undefined => { getAppRoot: (): string | undefined => {
/*
NOTE@coder: not sure where we could get this from. This is new.
@jsjoeio 3/11/21
*/
return (args.resolverEnv && args.resolverEnv['VSCODE_CWD']) || env['VSCODE_CWD'] || process.cwd(); return (args.resolverEnv && args.resolverEnv['VSCODE_CWD']) || env['VSCODE_CWD'] || process.cwd();
}, },
getExecPath: (): string | undefined => { getExecPath: (): string | undefined => {

View File

@ -1,108 +1,99 @@
import { field } from "@coder/logger" import { field } from '@coder/logger';
import { release } from "os" import { release } from 'os';
import * as fs from "fs" import * as fs from 'fs';
import * as net from "net" import * as net from 'net';
import * as path from "path" import * as path from 'path';
import { Emitter } from "vs/base/common/event" import { Emitter } from 'vs/base/common/event';
import { Schemas } from "vs/base/common/network" import { Schemas } from 'vs/base/common/network';
import { URI } from "vs/base/common/uri" import { URI } from 'vs/base/common/uri';
import { getMachineId } from "vs/base/node/id" import { getMachineId } from 'vs/base/node/id';
import { ClientConnectionEvent, IPCServer, IServerChannel, ProxyChannel } from "vs/base/parts/ipc/common/ipc" import { ClientConnectionEvent, IPCServer, IServerChannel, ProxyChannel } 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 { main } from "vs/code/node/cliProcessMain" import { main } from 'vs/code/node/cliProcessMain';
import { IConfigurationService } from "vs/platform/configuration/common/configuration" import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ConfigurationService } from "vs/platform/configuration/common/configurationService" import { ConfigurationService } from 'vs/platform/configuration/common/configurationService';
import { ExtensionHostDebugBroadcastChannel } from "vs/platform/debug/common/extensionHostDebugIpc" import { ExtensionHostDebugBroadcastChannel } from 'vs/platform/debug/common/extensionHostDebugIpc';
import { NativeParsedArgs } from "vs/platform/environment/common/argv" import { NativeParsedArgs } from 'vs/platform/environment/common/argv';
import { IEnvironmentService, INativeEnvironmentService } from "vs/platform/environment/common/environment" import { IEnvironmentService, INativeEnvironmentService } from 'vs/platform/environment/common/environment';
import { NativeEnvironmentService } from "vs/platform/environment/node/environmentService" import { NativeEnvironmentService } from 'vs/platform/environment/node/environmentService';
import { ExtensionGalleryService } from "vs/platform/extensionManagement/common/extensionGalleryService" import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService';
import { import { IExtensionGalleryService, IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement';
IExtensionGalleryService, import { ExtensionManagementChannel } from 'vs/platform/extensionManagement/common/extensionManagementIpc';
IExtensionManagementService, import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService';
} from "vs/platform/extensionManagement/common/extensionManagement" import { IFileService } from 'vs/platform/files/common/files';
import { ExtensionManagementChannel } from "vs/platform/extensionManagement/common/extensionManagementIpc" import { FileService } from 'vs/platform/files/common/fileService';
import { ExtensionManagementService } from "vs/platform/extensionManagement/node/extensionManagementService" import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider';
import { IFileService } from "vs/platform/files/common/files" import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { FileService } from "vs/platform/files/common/fileService" import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
import { DiskFileSystemProvider } from "vs/platform/files/node/diskFileSystemProvider" import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { SyncDescriptor } from "vs/platform/instantiation/common/descriptors" import { ILocalizationsService } from 'vs/platform/localizations/common/localizations';
import { InstantiationService } from "vs/platform/instantiation/common/instantiationService" import { LocalizationsService } from 'vs/platform/localizations/node/localizations';
import { ServiceCollection } from "vs/platform/instantiation/common/serviceCollection" import { ConsoleLogger, getLogLevel, ILoggerService, ILogService, MultiplexLogService } from 'vs/platform/log/common/log';
import { ILocalizationsService } from "vs/platform/localizations/common/localizations" import { LogLevelChannel } from 'vs/platform/log/common/logIpc';
import { LocalizationsService } from "vs/platform/localizations/node/localizations" import { LoggerService } from 'vs/platform/log/node/loggerService';
import { import { SpdLogLogger } from 'vs/platform/log/node/spdlogLog';
ConsoleLogger, import product from 'vs/platform/product/common/product';
getLogLevel, import { IProductService } from 'vs/platform/product/common/productService';
ILoggerService, import { ConnectionType, ConnectionTypeRequest } from 'vs/platform/remote/common/remoteAgentConnection';
ILogService, import { RemoteAgentConnectionContext } from 'vs/platform/remote/common/remoteAgentEnvironment';
MultiplexLogService, import { IRequestService } from 'vs/platform/request/common/request';
} from "vs/platform/log/common/log" import { RequestChannel } from 'vs/platform/request/common/requestIpc';
import { LogLevelChannel } from "vs/platform/log/common/logIpc" import { RequestService } from 'vs/platform/request/node/requestService';
import { LoggerService } from "vs/platform/log/node/loggerService" import ErrorTelemetry from 'vs/platform/telemetry/browser/errorTelemetry';
import { SpdLogLogger } from "vs/platform/log/node/spdlogLog" import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import product from "vs/platform/product/common/product" import { TelemetryLogAppender } from 'vs/platform/telemetry/common/telemetryLogAppender';
import { IProductService } from "vs/platform/product/common/productService" import { TelemetryService } from 'vs/platform/telemetry/common/telemetryService';
import { ConnectionType, ConnectionTypeRequest } from "vs/platform/remote/common/remoteAgentConnection" import { combinedAppender, NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils';
import { RemoteAgentConnectionContext } from "vs/platform/remote/common/remoteAgentEnvironment" import { AppInsightsAppender } from 'vs/platform/telemetry/node/appInsightsAppender';
import { IRequestService } from "vs/platform/request/common/request" import { resolveCommonProperties } from 'vs/platform/telemetry/common/commonProperties';
import { RequestChannel } from "vs/platform/request/common/requestIpc" import { TelemetryChannel } from 'vs/server/common/telemetry';
import { RequestService } from "vs/platform/request/node/requestService" import { Query, VscodeOptions, WorkbenchOptions } from 'vs/server/ipc';
import ErrorTelemetry from "vs/platform/telemetry/browser/errorTelemetry" import { ExtensionEnvironmentChannel, FileProviderChannel, TerminalProviderChannel } from 'vs/server/node/channel';
import { ITelemetryService } from "vs/platform/telemetry/common/telemetry" import { Connection, ExtensionHostConnection, ManagementConnection } from 'vs/server/node/connection';
import { TelemetryLogAppender } from "vs/platform/telemetry/common/telemetryLogAppender" import { TelemetryClient } from 'vs/server/node/insights';
import { TelemetryService } from "vs/platform/telemetry/common/telemetryService" import { logger } from 'vs/server/node/logger';
import { combinedAppender, NullTelemetryService } from "vs/platform/telemetry/common/telemetryUtils" import { getLocaleFromConfig, getNlsConfiguration } from 'vs/server/node/nls';
import { AppInsightsAppender } from "vs/platform/telemetry/node/appInsightsAppender" import { Protocol } from 'vs/server/node/protocol';
import { resolveCommonProperties } from "vs/platform/telemetry/common/commonProperties" import { getUriTransformer } from 'vs/server/node/util';
import { TelemetryChannel } from "vs/server/common/telemetry" import { REMOTE_TERMINAL_CHANNEL_NAME } from 'vs/workbench/contrib/terminal/common/remoteTerminalChannel';
import { Query, VscodeOptions, WorkbenchOptions } from "vs/server/ipc" import { REMOTE_FILE_SYSTEM_CHANNEL_NAME } from 'vs/workbench/services/remote/common/remoteAgentFileSystemChannel';
import { ExtensionEnvironmentChannel, FileProviderChannel, TerminalProviderChannel } from "vs/server/node/channel" import { RemoteExtensionLogFileName } from 'vs/workbench/services/remote/common/remoteAgentService';
import { Connection, ExtensionHostConnection, ManagementConnection } from "vs/server/node/connection"
import { TelemetryClient } from "vs/server/node/insights"
import { logger } from "vs/server/node/logger"
import { getLocaleFromConfig, getNlsConfiguration } from "vs/server/node/nls"
import { Protocol } from "vs/server/node/protocol"
import { getUriTransformer } from "vs/server/node/util"
import { REMOTE_TERMINAL_CHANNEL_NAME } from "vs/workbench/contrib/terminal/common/remoteTerminalChannel"
import { REMOTE_FILE_SYSTEM_CHANNEL_NAME } from "vs/workbench/services/remote/common/remoteAgentFileSystemChannel"
import { RemoteExtensionLogFileName } from "vs/workbench/services/remote/common/remoteAgentService"
export class Vscode { export class Vscode {
public readonly _onDidClientConnect = new Emitter<ClientConnectionEvent>() public readonly _onDidClientConnect = new Emitter<ClientConnectionEvent>();
public readonly onDidClientConnect = this._onDidClientConnect.event public readonly onDidClientConnect = this._onDidClientConnect.event;
private readonly ipc = new IPCServer<RemoteAgentConnectionContext>(this.onDidClientConnect) private readonly ipc = new IPCServer<RemoteAgentConnectionContext>(this.onDidClientConnect);
private readonly maxExtraOfflineConnections = 0 private readonly maxExtraOfflineConnections = 0;
private readonly connections = new Map<ConnectionType, Map<string, Connection>>() private readonly connections = new Map<ConnectionType, Map<string, Connection>>();
private readonly services = new ServiceCollection() private readonly services = new ServiceCollection();
private servicesPromise?: Promise<void> private servicesPromise?: Promise<void>;
public async cli(args: NativeParsedArgs): Promise<void> { public async cli(args: NativeParsedArgs): Promise<void> {
return main(args) return main(args);
} }
public async initialize(options: VscodeOptions): Promise<WorkbenchOptions> { public async initialize(options: VscodeOptions): Promise<WorkbenchOptions> {
const transformer = getUriTransformer(options.remoteAuthority) const transformer = getUriTransformer(options.remoteAuthority);
if (!this.servicesPromise) { if (!this.servicesPromise) {
this.servicesPromise = this.initializeServices(options.args) this.servicesPromise = this.initializeServices(options.args);
} }
await this.servicesPromise await this.servicesPromise;
const environment = this.services.get(IEnvironmentService) as INativeEnvironmentService const environment = this.services.get(IEnvironmentService) as INativeEnvironmentService;
const startPath = options.startPath const startPath = options.startPath;
const parseUrl = (url: string): URI => { const parseUrl = (url: string): URI => {
// This might be a fully-specified URL or just a path. // This might be a fully-specified URL or just a path.
try { try {
return URI.parse(url, true) return URI.parse(url, true);
} catch (error) { } catch (error) {
return URI.from({ return URI.from({
scheme: Schemas.vscodeRemote, scheme: Schemas.vscodeRemote,
authority: options.remoteAuthority, authority: options.remoteAuthority,
path: url, path: url,
}) });
} }
} };
return { return {
workbenchWebConfiguration: { workbenchWebConfiguration: {
workspaceUri: startPath && startPath.workspace ? parseUrl(startPath.url) : undefined, workspaceUri: startPath && startPath.workspace ? parseUrl(startPath.url) : undefined,
@ -111,112 +102,106 @@ export class Vscode {
logLevel: getLogLevel(environment), logLevel: getLogLevel(environment),
workspaceProvider: { workspaceProvider: {
payload: [ payload: [
["userDataPath", environment.userDataPath], ['userDataPath', environment.userDataPath],
["enableProposedApi", JSON.stringify(options.args["enable-proposed-api"] || [])], ['enableProposedApi', JSON.stringify(options.args['enable-proposed-api'] || [])]
], ],
}, },
}, },
remoteUserDataUri: transformer.transformOutgoing(URI.file(environment.userDataPath)), remoteUserDataUri: transformer.transformOutgoing(URI.file(environment.userDataPath)),
productConfiguration: product, productConfiguration: product,
nlsConfiguration: await getNlsConfiguration( nlsConfiguration: await getNlsConfiguration(environment.args.locale || await getLocaleFromConfig(environment.userDataPath), environment.userDataPath),
environment.args.locale || (await getLocaleFromConfig(environment.userDataPath)), commit: product.commit || 'development',
environment.userDataPath, };
),
commit: product.commit || "development",
}
} }
public async handleWebSocket(socket: net.Socket, query: Query, permessageDeflate: boolean): Promise<true> { public async handleWebSocket(socket: net.Socket, query: Query, permessageDeflate: boolean): Promise<true> {
if (!query.reconnectionToken) { if (!query.reconnectionToken) {
throw new Error("Reconnection token is missing from query parameters") throw new Error('Reconnection token is missing from query parameters');
} }
const protocol = new Protocol(socket, { const protocol = new Protocol(socket, {
reconnectionToken: <string>query.reconnectionToken, reconnectionToken: <string>query.reconnectionToken,
reconnection: query.reconnection === "true", reconnection: query.reconnection === 'true',
skipWebSocketFrames: query.skipWebSocketFrames === "true", skipWebSocketFrames: query.skipWebSocketFrames === 'true',
permessageDeflate, permessageDeflate,
recordInflateBytes: permessageDeflate, recordInflateBytes: permessageDeflate,
}) });
try { try {
await this.connect(await protocol.handshake(), protocol) await this.connect(await protocol.handshake(), protocol);
} catch (error) { } catch (error) {
protocol.sendMessage({ type: "error", reason: error.message }) protocol.sendMessage({ type: 'error', reason: error.message });
protocol.dispose() protocol.dispose();
protocol.getSocket().dispose() protocol.getSocket().dispose();
} }
return true return true;
} }
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) { if (product.commit && message.commit !== product.commit) {
logger.warn(`Version mismatch (${message.commit} instead of ${product.commit})`) logger.warn(`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:
if (!this.connections.has(message.desiredConnectionType)) { if (!this.connections.has(message.desiredConnectionType)) {
this.connections.set(message.desiredConnectionType, new Map()) this.connections.set(message.desiredConnectionType, new Map());
} }
const connections = this.connections.get(message.desiredConnectionType)! const connections = this.connections.get(message.desiredConnectionType)!;
const ok = async () => { const ok = async () => {
return message.desiredConnectionType === ConnectionType.ExtensionHost return message.desiredConnectionType === ConnectionType.ExtensionHost
? { debugPort: await this.getDebugPort() } ? { debugPort: await this.getDebugPort() }
: { type: "ok" } : { type: 'ok' };
} };
const token = protocol.options.reconnectionToken const token = protocol.options.reconnectionToken;
if (protocol.options.reconnection && connections.has(token)) { if (protocol.options.reconnection && connections.has(token)) {
protocol.sendMessage(await ok()) protocol.sendMessage(await ok());
const buffer = protocol.readEntireBuffer() const buffer = protocol.readEntireBuffer();
protocol.dispose() protocol.dispose();
return connections.get(token)!.reconnect(protocol.getSocket(), buffer) return connections.get(token)!.reconnect(protocol.getSocket(), buffer);
} else if (protocol.options.reconnection || connections.has(token)) { } else if (protocol.options.reconnection || connections.has(token)) {
throw new Error( throw new Error(protocol.options.reconnection
protocol.options.reconnection ? "Unrecognized reconnection token" : "Duplicate reconnection token", ? 'Unrecognized reconnection token'
) : 'Duplicate reconnection token'
);
} }
logger.debug("New connection", field("token", token)) logger.debug('New connection', field('token', token));
protocol.sendMessage(await ok()) protocol.sendMessage(await ok());
let connection: Connection let connection: Connection;
if (message.desiredConnectionType === ConnectionType.Management) { if (message.desiredConnectionType === ConnectionType.Management) {
connection = new ManagementConnection(protocol, token) connection = new ManagementConnection(protocol, token);
this._onDidClientConnect.fire({ this._onDidClientConnect.fire({
protocol, protocol, onDidClientDisconnect: connection.onClose,
onDidClientDisconnect: connection.onClose, });
})
} else { } else {
const buffer = protocol.readEntireBuffer() const buffer = protocol.readEntireBuffer();
connection = new ExtensionHostConnection( connection = new ExtensionHostConnection(
message.args ? message.args.language : "en", message.args ? message.args.language : 'en',
protocol, protocol, buffer, token,
buffer,
token,
this.services.get(IEnvironmentService) as INativeEnvironmentService, this.services.get(IEnvironmentService) as INativeEnvironmentService,
) );
} }
connections.set(token, connection) connections.set(token, connection);
connection.onClose(() => { connection.onClose(() => {
logger.debug("Connection closed", field("token", token)) logger.debug('Connection closed', field('token', token));
connections.delete(token) connections.delete(token);
}) });
this.disposeOldOfflineConnections(connections) this.disposeOldOfflineConnections(connections);
break break;
case ConnectionType.Tunnel: case ConnectionType.Tunnel: return protocol.tunnel();
return protocol.tunnel() default: throw new Error('Unrecognized connection type');
default:
throw new Error("Unrecognized connection type")
} }
} }
private disposeOldOfflineConnections(connections: Map<string, Connection>): void { private disposeOldOfflineConnections(connections: Map<string, Connection>): void {
const offline = Array.from(connections.values()).filter((connection) => typeof connection.offline !== "undefined") const offline = Array.from(connections.values())
.filter((connection) => typeof connection.offline !== 'undefined');
for (let i = 0, max = offline.length - this.maxExtraOfflineConnections; i < max; ++i) { for (let i = 0, max = offline.length - this.maxExtraOfflineConnections; i < max; ++i) {
logger.debug("Disposing offline connection", field("token", offline[i].token)) logger.debug('Disposing offline connection', field('token', offline[i].token));
offline[i].dispose() offline[i].dispose();
} }
} }
@ -228,9 +213,9 @@ export class Vscode {
If upstream changes cause conflicts, look there ^. If upstream changes cause conflicts, look there ^.
3/11/21 @jsjoeio 3/11/21 @jsjoeio
*/ */
const environmentService = new NativeEnvironmentService(args) const environmentService = new NativeEnvironmentService(args);
// https://github.com/cdr/code-server/issues/1693 // https://github.com/cdr/code-server/issues/1693
fs.mkdirSync(environmentService.globalStorageHome.fsPath, { recursive: true }) fs.mkdirSync(environmentService.globalStorageHome.fsPath, { recursive: true });
/* /*
NOTE@coder: Made these updates on based on this file (and lines): NOTE@coder: Made these updates on based on this file (and lines):
Reference: - ../../electron-browser/sharedProcess/sharedProcessMain.ts#L144-L149 Reference: - ../../electron-browser/sharedProcess/sharedProcessMain.ts#L144-L149
@ -243,133 +228,91 @@ export class Vscode {
*/ */
const logService = new MultiplexLogService([ const logService = new MultiplexLogService([
new ConsoleLogger(getLogLevel(environmentService)), new ConsoleLogger(getLogLevel(environmentService)),
new SpdLogLogger( new SpdLogLogger(RemoteExtensionLogFileName, path.join(environmentService.logsPath, `${RemoteExtensionLogFileName}.log`), false, getLogLevel(environmentService))
RemoteExtensionLogFileName, ]);
path.join(environmentService.logsPath, `${RemoteExtensionLogFileName}.log`), const fileService = new FileService(logService);
false, fileService.registerProvider(Schemas.file, new DiskFileSystemProvider(logService));
getLogLevel(environmentService),
),
])
const fileService = new FileService(logService)
fileService.registerProvider(Schemas.file, new DiskFileSystemProvider(logService))
const loggerService = new LoggerService(logService, fileService) const loggerService = new LoggerService(logService, fileService);
const piiPaths = [ const piiPaths = [
path.join(environmentService.userDataPath, "clp"), // Language packs. path.join(environmentService.userDataPath, 'clp'), // Language packs.
environmentService.appRoot, environmentService.appRoot,
environmentService.extensionsPath, environmentService.extensionsPath,
environmentService.builtinExtensionsPath, environmentService.builtinExtensionsPath,
...environmentService.extraExtensionPaths, ...environmentService.extraExtensionPaths,
...environmentService.extraBuiltinExtensionPaths, ...environmentService.extraBuiltinExtensionPaths,
] ];
/* this.ipc.registerChannel('logger', new LogLevelChannel(logService));
NOTE@coder: we changed this channel registration from LogLevel to LogLevelChannel this.ipc.registerChannel(ExtensionHostDebugBroadcastChannel.ChannelName, new ExtensionHostDebugBroadcastChannel());
because it changed upstream.
3/15/21 jsjoeio this.services.set(ILogService, logService);
*/ this.services.set(IEnvironmentService, environmentService);
this.ipc.registerChannel("logger", new LogLevelChannel(logService)) this.services.set(INativeEnvironmentService, environmentService);
this.ipc.registerChannel(ExtensionHostDebugBroadcastChannel.ChannelName, new ExtensionHostDebugBroadcastChannel()) this.services.set(ILoggerService, loggerService);
this.services.set(ILogService, logService) const configurationService = new ConfigurationService(environmentService.settingsResource, fileService);
this.services.set(IEnvironmentService, environmentService) await configurationService.initialize();
this.services.set(INativeEnvironmentService, environmentService) this.services.set(IConfigurationService, configurationService);
/*
NOTE@coder: we changed this from LoggerService to the loggerService defined above.
3/11/21 @jsjoeio
*/
this.services.set(ILoggerService, loggerService)
const configurationService = new ConfigurationService(environmentService.settingsResource, fileService) this.services.set(IRequestService, new SyncDescriptor(RequestService));
await configurationService.initialize() this.services.set(IFileService, fileService);
this.services.set(IConfigurationService, configurationService) this.services.set(IProductService, { _serviceBrand: undefined, ...product });
this.services.set(IRequestService, new SyncDescriptor(RequestService)) const machineId = await getMachineId();
this.services.set(IFileService, fileService)
this.services.set(IProductService, { _serviceBrand: undefined, ...product })
const machineId = await getMachineId()
await new Promise((resolve) => { await new Promise((resolve) => {
const instantiationService = new InstantiationService(this.services) const instantiationService = new InstantiationService(this.services);
instantiationService.invokeFunction((accessor) => { instantiationService.invokeFunction((accessor) => {
instantiationService.createInstance(LogsDataCleaner) instantiationService.createInstance(LogsDataCleaner);
let telemetryService: ITelemetryService let telemetryService: ITelemetryService;
if (!environmentService.disableTelemetry) { if (!environmentService.disableTelemetry) {
telemetryService = new TelemetryService( telemetryService = new TelemetryService({
{ appender: combinedAppender(
appender: combinedAppender( new AppInsightsAppender('code-server', null, () => new TelemetryClient() as any),
new AppInsightsAppender("code-server", null, () => new TelemetryClient() as any), new TelemetryLogAppender(accessor.get(ILoggerService), environmentService)
new TelemetryLogAppender(accessor.get(ILoggerService), environmentService), ),
), sendErrorTelemetry: true,
sendErrorTelemetry: true, commonProperties: resolveCommonProperties(
commonProperties: resolveCommonProperties( fileService, release(), process.arch, product.commit, product.version, machineId,
fileService, [], environmentService.installSourcePath, 'code-server',
release(), ),
process.arch, piiPaths,
product.commit, }, configurationService);
product.version,
machineId,
[],
environmentService.installSourcePath,
"code-server",
),
piiPaths,
},
configurationService,
)
} else { } else {
telemetryService = NullTelemetryService telemetryService = NullTelemetryService;
} }
this.services.set(ITelemetryService, telemetryService) this.services.set(ITelemetryService, telemetryService);
this.services.set(IExtensionManagementService, new SyncDescriptor(ExtensionManagementService)) this.services.set(IExtensionManagementService, new SyncDescriptor(ExtensionManagementService));
this.services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryService)) this.services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryService));
this.services.set(ILocalizationsService, new SyncDescriptor(LocalizationsService)) this.services.set(ILocalizationsService, new SyncDescriptor(LocalizationsService));
this.ipc.registerChannel( this.ipc.registerChannel('extensions', new ExtensionManagementChannel(
"extensions", accessor.get(IExtensionManagementService),
new ExtensionManagementChannel(accessor.get(IExtensionManagementService), (context) => (context) => getUriTransformer(context.remoteAuthority),
getUriTransformer(context.remoteAuthority), ));
), this.ipc.registerChannel('remoteextensionsenvironment', new ExtensionEnvironmentChannel(
) environmentService, logService, telemetryService, '',
this.ipc.registerChannel( ));
"remoteextensionsenvironment", this.ipc.registerChannel('request', new RequestChannel(accessor.get(IRequestService)));
new ExtensionEnvironmentChannel(environmentService, logService, telemetryService, ""), this.ipc.registerChannel('telemetry', new TelemetryChannel(telemetryService));
) this.ipc.registerChannel('localizations', <IServerChannel<any>>ProxyChannel.fromService(accessor.get(ILocalizationsService)));
this.ipc.registerChannel("request", new RequestChannel(accessor.get(IRequestService))) this.ipc.registerChannel(REMOTE_FILE_SYSTEM_CHANNEL_NAME, new FileProviderChannel(environmentService, logService));
this.ipc.registerChannel("telemetry", new TelemetryChannel(telemetryService)) this.ipc.registerChannel(REMOTE_TERMINAL_CHANNEL_NAME, new TerminalProviderChannel(logService));
/* resolve(new ErrorTelemetry(telemetryService));
NOTE@coder: they renamed createChannelReceiver and made it part of the ProxyChannel namespace });
See: https://github.com/microsoft/vscode/commit/e371faebfb679ca0dcdb61f4f2f33b3d69922a77 });
And see this as an example similar to our code below:
https://github.com/microsoft/vscode/blob/e371faebfb679ca0dcdb61f4f2f33b3d69922a77/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts#L273
3/11/2021 by @jsjoeio
*/
this.ipc.registerChannel(
"localizations",
<IServerChannel<any>>ProxyChannel.fromService(accessor.get(ILocalizationsService)),
)
this.ipc.registerChannel(
REMOTE_FILE_SYSTEM_CHANNEL_NAME,
new FileProviderChannel(environmentService, logService),
)
this.ipc.registerChannel(REMOTE_TERMINAL_CHANNEL_NAME, new TerminalProviderChannel(logService))
resolve(new ErrorTelemetry(telemetryService))
})
})
} }
/** /**
* TODO: implement. * TODO: implement.
*/ */
private async getDebugPort(): Promise<number | undefined> { private async getDebugPort(): Promise<number | undefined> {
return undefined return undefined;
} }
} }

View File

@ -0,0 +1,91 @@
import { chromium, Page, Browser, BrowserContext, Cookie } from "playwright"
import { hash } from "../../src/node/util"
import { CODE_SERVER_ADDRESS, PASSWORD, STORAGE, E2E_VIDEO_DIR } from "../utils/constants"
import { createCookieIfDoesntExist } from "../utils/helpers"
describe("Open Help > About", () => {
let browser: Browser
let page: Page
let context: BrowserContext
beforeAll(async () => {
browser = await chromium.launch()
// Create a new context with the saved storage state
const storageState = JSON.parse(STORAGE) || {}
const cookieToStore = {
sameSite: "Lax" as const,
name: "key",
value: hash(PASSWORD),
domain: "localhost",
path: "/",
expires: -1,
httpOnly: false,
secure: false,
}
// For some odd reason, the login method used in globalSetup.ts doesn't always work
// I don't know if it's on playwright clearing our cookies by accident
// or if it's our cookies disappearing.
// This means we need an additional check to make sure we're logged in.
// We do this by manually adding the cookie to the browser environment
// if it's not there at the time the test starts
const cookies: Cookie[] = storageState.cookies || []
// If the cookie exists in cookies then
// this will return the cookies with no changes
// otherwise if it doesn't exist, it will create it
// hence the name maybeUpdatedCookies
//
// TODO(@jsjoeio)
// The playwright storage thing sometimes works and sometimes doesn't. We should investigate this further
// at some point.
// See discussion: https://github.com/cdr/code-server/pull/2648#discussion_r575434946
const maybeUpdatedCookies = createCookieIfDoesntExist(cookies, cookieToStore)
context = await browser.newContext({
storageState: { cookies: maybeUpdatedCookies },
recordVideo: { dir: E2E_VIDEO_DIR },
})
})
afterAll(async () => {
// Remove password from local storage
await context.clearCookies()
await context.close()
await browser.close()
})
beforeEach(async () => {
page = await context.newPage()
})
it("should see a 'Help' then 'About' button in the Application Menu that opens a dialog", async () => {
// waitUntil: "domcontentloaded"
// In case the page takes a long time to load
await page.goto(CODE_SERVER_ADDRESS, { waitUntil: "domcontentloaded" })
// Make sure the editor actually loaded
expect(await page.isVisible("div.monaco-workbench"))
// Click the Application menu
await page.click("[aria-label='Application Menu']")
// See the Help button
const helpButton = "a.action-menu-item span[aria-label='Help']"
expect(await page.isVisible(helpButton))
// Hover the helpButton
await page.hover(helpButton)
// see the About button and click it
const aboutButton = "a.action-menu-item span[aria-label='About']"
expect(await page.isVisible(aboutButton))
// NOTE: it won't work unless you hover it first
await page.hover(aboutButton)
await page.click(aboutButton)
const codeServerText = "text=code-server"
expect(await page.isVisible(codeServerText))
})
})

View File

@ -7,7 +7,7 @@ const config: Config.InitialOptions = {
}, },
globalSetup: "<rootDir>/utils/globalSetup.ts", globalSetup: "<rootDir>/utils/globalSetup.ts",
testEnvironment: "node", testEnvironment: "node",
testPathIgnorePatterns: ["node_modules", "lib", "out", "test/unit"], testPathIgnorePatterns: ["/node_modules/", "/lib/", "/out/", "test/unit"],
testTimeout: 30000, testTimeout: 30000,
modulePathIgnorePatterns: [ modulePathIgnorePatterns: [
"<rootDir>/../lib/vscode", "<rootDir>/../lib/vscode",

View File

@ -1,4 +1,5 @@
{ {
"license": "MIT",
"#": "We must put jest in a sub-directory otherwise VS Code somehow picks up the types and generates conflicts with mocha.", "#": "We must put jest in a sub-directory otherwise VS Code somehow picks up the types and generates conflicts with mocha.",
"devDependencies": { "devDependencies": {
"@types/jest": "^26.0.20", "@types/jest": "^26.0.20",