mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-07 09:35:41 -05:00
* Fix initial build breaks from 1.67 merge (#2514) * Update yarn lock files * Update build scripts * Fix tsconfig * Build breaks * WIP * Update yarn lock files * Misc breaks * Updates to package.json * Breaks * Update yarn * Fix breaks * Breaks * Build breaks * Breaks * Breaks * Breaks * Breaks * Breaks * Missing file * Breaks * Breaks * Breaks * Breaks * Breaks * Fix several runtime breaks (#2515) * Missing files * Runtime breaks * Fix proxy ordering issue * Remove commented code * Fix breaks with opening query editor * Fix post merge break * Updates related to setup build and other breaks (#2516) * Fix bundle build issues * Update distro * Fix distro merge and update build JS files * Disable pipeline steps * Remove stats call * Update license name * Make new RPM dependencies a warning * Fix extension manager version checks * Update JS file * Fix a few runtime breaks * Fixes * Fix runtime issues * Fix build breaks * Update notebook tests (part 1) * Fix broken tests * Linting errors * Fix hygiene * Disable lint rules * Bump distro * Turn off smoke tests * Disable integration tests * Remove failing "activate" test * Remove failed test assertion * Disable other broken test * Disable query history tests * Disable extension unit tests * Disable failing tasks
371 lines
16 KiB
TypeScript
371 lines
16 KiB
TypeScript
/*---------------------------------------------------------------------------------------------
|
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
|
*--------------------------------------------------------------------------------------------*/
|
|
|
|
import { Event } from 'vs/base/common/event';
|
|
import * as platform from 'vs/base/common/platform';
|
|
import * as performance from 'vs/base/common/performance';
|
|
import { URI } from 'vs/base/common/uri';
|
|
import { createURITransformer } from 'vs/workbench/api/node/uriTransformer';
|
|
import { IRemoteAgentEnvironmentDTO, IGetEnvironmentDataArguments, IScanExtensionsArguments, IScanSingleExtensionArguments, IGetExtensionHostExitInfoArguments } from 'vs/workbench/services/remote/common/remoteAgentEnvironmentChannel';
|
|
import * as nls from 'vs/nls';
|
|
import { Schemas } from 'vs/base/common/network';
|
|
import { IServerEnvironmentService } from 'vs/server/node/serverEnvironmentService';
|
|
import { IServerChannel } from 'vs/base/parts/ipc/common/ipc';
|
|
import { ExtensionIdentifier, ExtensionType, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
|
import { transformOutgoingURIs } from 'vs/base/common/uriIpc';
|
|
import { ILogService } from 'vs/platform/log/common/log';
|
|
import { ContextKeyExpr, ContextKeyDefinedExpr, ContextKeyNotExpr, ContextKeyEqualsExpr, ContextKeyNotEqualsExpr, ContextKeyRegexExpr, IContextKeyExprMapper, ContextKeyExpression, ContextKeyInExpr, ContextKeyGreaterExpr, ContextKeyGreaterEqualsExpr, ContextKeySmallerExpr, ContextKeySmallerEqualsExpr } from 'vs/platform/contextkey/common/contextkey';
|
|
import { listProcesses } from 'vs/base/node/ps';
|
|
import { getMachineInfo, collectWorkspaceStats } from 'vs/platform/diagnostics/node/diagnosticsService';
|
|
import { IDiagnosticInfoOptions, IDiagnosticInfo } from 'vs/platform/diagnostics/common/diagnostics';
|
|
import { basename, isAbsolute, join, resolve } from 'vs/base/common/path';
|
|
import { ProcessItem } from 'vs/base/common/processes';
|
|
import { IExtensionManagementCLIService, InstallOptions } from 'vs/platform/extensionManagement/common/extensionManagement';
|
|
import { cwd } from 'vs/base/common/process';
|
|
import { ServerConnectionToken, ServerConnectionTokenType } from 'vs/server/node/serverConnectionToken';
|
|
import { IExtensionHostStatusService } from 'vs/server/node/extensionHostStatusService';
|
|
import { IExtensionsScannerService, toExtensionDescription } from 'vs/platform/extensionManagement/common/extensionsScannerService';
|
|
|
|
export class RemoteAgentEnvironmentChannel implements IServerChannel {
|
|
|
|
private static _namePool = 1;
|
|
|
|
private readonly whenExtensionsReady: Promise<void>;
|
|
|
|
constructor(
|
|
private readonly _connectionToken: ServerConnectionToken,
|
|
private readonly _environmentService: IServerEnvironmentService,
|
|
extensionManagementCLIService: IExtensionManagementCLIService,
|
|
private readonly _logService: ILogService,
|
|
private readonly _extensionHostStatusService: IExtensionHostStatusService,
|
|
private readonly _extensionsScannerService: IExtensionsScannerService,
|
|
) {
|
|
if (_environmentService.args['install-builtin-extension']) {
|
|
const installOptions: InstallOptions = { isMachineScoped: !!_environmentService.args['do-not-sync'], installPreReleaseVersion: !!_environmentService.args['pre-release'] };
|
|
this.whenExtensionsReady = extensionManagementCLIService.installExtensions([], _environmentService.args['install-builtin-extension'], installOptions, !!_environmentService.args['force'])
|
|
.then(null, error => {
|
|
_logService.error(error);
|
|
});
|
|
} else {
|
|
this.whenExtensionsReady = Promise.resolve();
|
|
}
|
|
|
|
const extensionsToInstall = _environmentService.args['install-extension'];
|
|
if (extensionsToInstall) {
|
|
const idsOrVSIX = extensionsToInstall.map(input => /\.vsix$/i.test(input) ? URI.file(isAbsolute(input) ? input : join(cwd(), input)) : input);
|
|
this.whenExtensionsReady
|
|
.then(() => extensionManagementCLIService.installExtensions(idsOrVSIX, [], { isMachineScoped: !!_environmentService.args['do-not-sync'], installPreReleaseVersion: !!_environmentService.args['pre-release'] }, !!_environmentService.args['force']))
|
|
.then(null, error => {
|
|
_logService.error(error);
|
|
});
|
|
}
|
|
}
|
|
|
|
async call(_: any, command: string, arg?: any): Promise<any> {
|
|
switch (command) {
|
|
|
|
case 'getEnvironmentData': {
|
|
const args = <IGetEnvironmentDataArguments>arg;
|
|
const uriTransformer = createURITransformer(args.remoteAuthority);
|
|
|
|
let environmentData = await this._getEnvironmentData();
|
|
environmentData = transformOutgoingURIs(environmentData, uriTransformer);
|
|
|
|
return environmentData;
|
|
}
|
|
|
|
case 'getExtensionHostExitInfo': {
|
|
const args = <IGetExtensionHostExitInfoArguments>arg;
|
|
return this._extensionHostStatusService.getExitInfo(args.reconnectionToken);
|
|
}
|
|
|
|
case 'whenExtensionsReady': {
|
|
await this.whenExtensionsReady;
|
|
return;
|
|
}
|
|
|
|
case 'scanExtensions': {
|
|
await this.whenExtensionsReady;
|
|
const args = <IScanExtensionsArguments>arg;
|
|
const language = args.language;
|
|
this._logService.trace(`Scanning extensions using UI language: ${language}`);
|
|
const uriTransformer = createURITransformer(args.remoteAuthority);
|
|
|
|
const extensionDevelopmentLocations = args.extensionDevelopmentPath && args.extensionDevelopmentPath.map(url => URI.revive(uriTransformer.transformIncoming(url)));
|
|
const extensionDevelopmentPath = extensionDevelopmentLocations ? extensionDevelopmentLocations.filter(url => url.scheme === Schemas.file).map(url => url.fsPath) : undefined;
|
|
|
|
let extensions = await this._scanExtensions(language, extensionDevelopmentPath);
|
|
extensions = transformOutgoingURIs(extensions, uriTransformer);
|
|
|
|
this._logService.trace('Scanned Extensions', extensions);
|
|
RemoteAgentEnvironmentChannel._massageWhenConditions(extensions);
|
|
|
|
return extensions;
|
|
}
|
|
|
|
case 'scanSingleExtension': {
|
|
await this.whenExtensionsReady;
|
|
const args = <IScanSingleExtensionArguments>arg;
|
|
const language = args.language;
|
|
const isBuiltin = args.isBuiltin;
|
|
const uriTransformer = createURITransformer(args.remoteAuthority);
|
|
const extensionLocation = URI.revive(uriTransformer.transformIncoming(args.extensionLocation));
|
|
const extensionPath = extensionLocation.scheme === Schemas.file ? extensionLocation.fsPath : null;
|
|
|
|
if (!extensionPath) {
|
|
return null;
|
|
}
|
|
|
|
let extension = await this._scanSingleExtension(extensionPath, isBuiltin, language);
|
|
|
|
if (!extension) {
|
|
return null;
|
|
}
|
|
|
|
extension = transformOutgoingURIs(extension, uriTransformer);
|
|
|
|
RemoteAgentEnvironmentChannel._massageWhenConditions([extension]);
|
|
|
|
return extension;
|
|
}
|
|
|
|
case 'getDiagnosticInfo': {
|
|
const options = <IDiagnosticInfoOptions>arg;
|
|
const diagnosticInfo: IDiagnosticInfo = {
|
|
machineInfo: getMachineInfo()
|
|
};
|
|
|
|
const processesPromise: Promise<ProcessItem | void> = options.includeProcesses ? listProcesses(process.pid) : Promise.resolve();
|
|
|
|
let workspaceMetadataPromises: Promise<void>[] = [];
|
|
const workspaceMetadata: { [key: string]: any } = {};
|
|
if (options.folders) {
|
|
// only incoming paths are transformed, so remote authority is unneeded.
|
|
const uriTransformer = createURITransformer('');
|
|
const folderPaths = options.folders
|
|
.map(folder => URI.revive(uriTransformer.transformIncoming(folder)))
|
|
.filter(uri => uri.scheme === 'file');
|
|
|
|
workspaceMetadataPromises = folderPaths.map(folder => {
|
|
return collectWorkspaceStats(folder.fsPath, ['node_modules', '.git'])
|
|
.then(stats => {
|
|
workspaceMetadata[basename(folder.fsPath)] = stats;
|
|
});
|
|
});
|
|
}
|
|
|
|
return Promise.all([processesPromise, ...workspaceMetadataPromises]).then(([processes, _]) => {
|
|
diagnosticInfo.processes = processes || undefined;
|
|
diagnosticInfo.workspaceMetadata = options.folders ? workspaceMetadata : undefined;
|
|
return diagnosticInfo;
|
|
});
|
|
}
|
|
}
|
|
|
|
throw new Error(`IPC Command ${command} not found`);
|
|
}
|
|
|
|
listen(_: any, event: string, arg: any): Event<any> {
|
|
throw new Error('Not supported');
|
|
}
|
|
|
|
private static _massageWhenConditions(extensions: IExtensionDescription[]): void {
|
|
// Massage "when" conditions which mention `resourceScheme`
|
|
|
|
interface WhenUser { when?: string }
|
|
|
|
interface LocWhenUser { [loc: string]: WhenUser[] }
|
|
|
|
const _mapResourceSchemeValue = (value: string, isRegex: boolean): string => {
|
|
// console.log(`_mapResourceSchemeValue: ${value}, ${isRegex}`);
|
|
return value.replace(/file/g, 'vscode-remote');
|
|
};
|
|
|
|
const _mapResourceRegExpValue = (value: RegExp): RegExp => {
|
|
let flags = '';
|
|
flags += value.global ? 'g' : '';
|
|
flags += value.ignoreCase ? 'i' : '';
|
|
flags += value.multiline ? 'm' : '';
|
|
return new RegExp(_mapResourceSchemeValue(value.source, true), flags);
|
|
};
|
|
|
|
const _exprKeyMapper = new class implements IContextKeyExprMapper {
|
|
mapDefined(key: string): ContextKeyExpression {
|
|
return ContextKeyDefinedExpr.create(key);
|
|
}
|
|
mapNot(key: string): ContextKeyExpression {
|
|
return ContextKeyNotExpr.create(key);
|
|
}
|
|
mapEquals(key: string, value: any): ContextKeyExpression {
|
|
if (key === 'resourceScheme' && typeof value === 'string') {
|
|
return ContextKeyEqualsExpr.create(key, _mapResourceSchemeValue(value, false));
|
|
} else {
|
|
return ContextKeyEqualsExpr.create(key, value);
|
|
}
|
|
}
|
|
mapNotEquals(key: string, value: any): ContextKeyExpression {
|
|
if (key === 'resourceScheme' && typeof value === 'string') {
|
|
return ContextKeyNotEqualsExpr.create(key, _mapResourceSchemeValue(value, false));
|
|
} else {
|
|
return ContextKeyNotEqualsExpr.create(key, value);
|
|
}
|
|
}
|
|
mapGreater(key: string, value: any): ContextKeyExpression {
|
|
return ContextKeyGreaterExpr.create(key, value);
|
|
}
|
|
mapGreaterEquals(key: string, value: any): ContextKeyExpression {
|
|
return ContextKeyGreaterEqualsExpr.create(key, value);
|
|
}
|
|
mapSmaller(key: string, value: any): ContextKeyExpression {
|
|
return ContextKeySmallerExpr.create(key, value);
|
|
}
|
|
mapSmallerEquals(key: string, value: any): ContextKeyExpression {
|
|
return ContextKeySmallerEqualsExpr.create(key, value);
|
|
}
|
|
mapRegex(key: string, regexp: RegExp | null): ContextKeyRegexExpr {
|
|
if (key === 'resourceScheme' && regexp) {
|
|
return ContextKeyRegexExpr.create(key, _mapResourceRegExpValue(regexp));
|
|
} else {
|
|
return ContextKeyRegexExpr.create(key, regexp);
|
|
}
|
|
}
|
|
mapIn(key: string, valueKey: string): ContextKeyInExpr {
|
|
return ContextKeyInExpr.create(key, valueKey);
|
|
}
|
|
};
|
|
|
|
const _massageWhenUser = (element: WhenUser) => {
|
|
if (!element || !element.when || !/resourceScheme/.test(element.when)) {
|
|
return;
|
|
}
|
|
|
|
const expr = ContextKeyExpr.deserialize(element.when);
|
|
if (!expr) {
|
|
return;
|
|
}
|
|
|
|
const massaged = expr.map(_exprKeyMapper);
|
|
element.when = massaged.serialize();
|
|
};
|
|
|
|
const _massageWhenUserArr = (elements: WhenUser[] | WhenUser) => {
|
|
if (Array.isArray(elements)) {
|
|
for (let element of elements) {
|
|
_massageWhenUser(element);
|
|
}
|
|
} else {
|
|
_massageWhenUser(elements);
|
|
}
|
|
};
|
|
|
|
const _massageLocWhenUser = (target: LocWhenUser) => {
|
|
for (let loc in target) {
|
|
_massageWhenUserArr(target[loc]);
|
|
}
|
|
};
|
|
|
|
extensions.forEach((extension) => {
|
|
if (extension.contributes) {
|
|
if (extension.contributes.menus) {
|
|
_massageLocWhenUser(<LocWhenUser>extension.contributes.menus);
|
|
}
|
|
if (extension.contributes.keybindings) {
|
|
_massageWhenUserArr(<WhenUser | WhenUser[]>extension.contributes.keybindings);
|
|
}
|
|
if (extension.contributes.views) {
|
|
_massageLocWhenUser(<LocWhenUser>extension.contributes.views);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
private async _getEnvironmentData(): Promise<IRemoteAgentEnvironmentDTO> {
|
|
return {
|
|
pid: process.pid,
|
|
connectionToken: (this._connectionToken.type !== ServerConnectionTokenType.None ? this._connectionToken.value : ''),
|
|
appRoot: URI.file(this._environmentService.appRoot),
|
|
settingsPath: this._environmentService.machineSettingsResource,
|
|
logsPath: URI.file(this._environmentService.logsPath),
|
|
extensionsPath: URI.file(this._environmentService.extensionsPath!),
|
|
extensionHostLogsPath: URI.file(join(this._environmentService.logsPath, `exthost${RemoteAgentEnvironmentChannel._namePool++}`)),
|
|
globalStorageHome: this._environmentService.globalStorageHome,
|
|
workspaceStorageHome: this._environmentService.workspaceStorageHome,
|
|
localHistoryHome: this._environmentService.localHistoryHome,
|
|
userHome: this._environmentService.userHome,
|
|
os: platform.OS,
|
|
arch: process.arch,
|
|
marks: performance.getMarks(),
|
|
useHostProxy: !!this._environmentService.args['use-host-proxy']
|
|
};
|
|
}
|
|
|
|
private async _scanExtensions(language: string, extensionDevelopmentPath?: string[]): Promise<IExtensionDescription[]> {
|
|
// Ensure that the language packs are available
|
|
|
|
const [builtinExtensions, installedExtensions, developedExtensions] = await Promise.all([
|
|
this._scanBuiltinExtensions(language),
|
|
this._scanInstalledExtensions(language),
|
|
this._scanDevelopedExtensions(language, extensionDevelopmentPath)
|
|
]);
|
|
|
|
let result = new Map<string, IExtensionDescription>();
|
|
|
|
builtinExtensions.forEach((builtinExtension) => {
|
|
if (!builtinExtension) {
|
|
return;
|
|
}
|
|
result.set(ExtensionIdentifier.toKey(builtinExtension.identifier), builtinExtension);
|
|
});
|
|
|
|
installedExtensions.forEach((installedExtension) => {
|
|
if (!installedExtension) {
|
|
return;
|
|
}
|
|
if (result.has(ExtensionIdentifier.toKey(installedExtension.identifier))) {
|
|
console.warn(nls.localize('overwritingExtension', "Overwriting extension {0} with {1}.", result.get(ExtensionIdentifier.toKey(installedExtension.identifier))!.extensionLocation.fsPath, installedExtension.extensionLocation.fsPath));
|
|
}
|
|
result.set(ExtensionIdentifier.toKey(installedExtension.identifier), installedExtension);
|
|
});
|
|
|
|
developedExtensions.forEach((developedExtension) => {
|
|
if (!developedExtension) {
|
|
return;
|
|
}
|
|
result.set(ExtensionIdentifier.toKey(developedExtension.identifier), developedExtension);
|
|
});
|
|
|
|
const r: IExtensionDescription[] = [];
|
|
result.forEach((v) => r.push(v));
|
|
return r;
|
|
}
|
|
|
|
private async _scanDevelopedExtensions(language: string, extensionDevelopmentPaths?: string[]): Promise<IExtensionDescription[]> {
|
|
if (extensionDevelopmentPaths) {
|
|
return (await Promise.all(extensionDevelopmentPaths.map(extensionDevelopmentPath => this._extensionsScannerService.scanOneOrMultipleExtensions(URI.file(resolve(extensionDevelopmentPath)), ExtensionType.User, { language }))))
|
|
.flat()
|
|
.map(e => toExtensionDescription(e, true));
|
|
}
|
|
return [];
|
|
}
|
|
|
|
private async _scanBuiltinExtensions(language: string): Promise<IExtensionDescription[]> {
|
|
const scannedExtensions = await this._extensionsScannerService.scanSystemExtensions({ language, useCache: true });
|
|
return scannedExtensions.map(e => toExtensionDescription(e, false));
|
|
}
|
|
|
|
private async _scanInstalledExtensions(language: string): Promise<IExtensionDescription[]> {
|
|
const scannedExtensions = await this._extensionsScannerService.scanUserExtensions({ language, useCache: true });
|
|
return scannedExtensions.map(e => toExtensionDescription(e, false));
|
|
}
|
|
|
|
private async _scanSingleExtension(extensionPath: string, isBuiltin: boolean, language: string): Promise<IExtensionDescription | null> {
|
|
const extensionLocation = URI.file(resolve(extensionPath));
|
|
const type = isBuiltin ? ExtensionType.System : ExtensionType.User;
|
|
const scannedExtension = await this._extensionsScannerService.scanExistingExtension(extensionLocation, type, { language });
|
|
return scannedExtension ? toExtensionDescription(scannedExtension, false) : null;
|
|
}
|
|
|
|
}
|