mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-13 03:28:33 -05:00
Merge from vscode 2b0b9136329c181a9e381463a1f7dc3a2d105a34 (#4880)
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { IRemoteConsoleLog } from 'vs/base/common/console';
|
||||
|
||||
export const IExtensionHostDebugService = createDecorator<IExtensionHostDebugService>('extensionHostDebugService');
|
||||
|
||||
export interface IExtensionHostDebugService {
|
||||
_serviceBrand: any;
|
||||
|
||||
reload(resource: URI): void;
|
||||
onReload: Event<URI>;
|
||||
|
||||
close(resource: URI): void;
|
||||
onClose: Event<URI>;
|
||||
|
||||
attachSession(id: string, port: number): void;
|
||||
onAttachSession: Event<{ id: string, port: number }>;
|
||||
|
||||
logToSession(id: string, log: IRemoteConsoleLog): void;
|
||||
onLogToSession: Event<{ id: string, log: IRemoteConsoleLog }>;
|
||||
|
||||
terminateSession(id: string): void;
|
||||
onTerminateSession: Event<string>;
|
||||
}
|
||||
@@ -134,7 +134,7 @@ export class CachedExtensionScanner {
|
||||
}
|
||||
|
||||
try {
|
||||
await pfs.del(cacheFile);
|
||||
await pfs.rimraf(cacheFile, pfs.RimRafMode.MOVE);
|
||||
} catch (err) {
|
||||
errors.onUnexpectedError(err);
|
||||
console.error(err);
|
||||
|
||||
@@ -21,9 +21,7 @@ import { findFreePort, randomPort } from 'vs/base/node/ports';
|
||||
import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc';
|
||||
import { PersistentProtocol } from 'vs/base/parts/ipc/common/ipc.net';
|
||||
import { generateRandomPipeName, NodeSocket } from 'vs/base/parts/ipc/node/ipc.net';
|
||||
import { IBroadcast, IBroadcastService } from 'vs/workbench/services/broadcast/common/broadcast';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { EXTENSION_ATTACH_BROADCAST_CHANNEL, EXTENSION_CLOSE_EXTHOST_BROADCAST_CHANNEL, EXTENSION_LOG_BROADCAST_CHANNEL, EXTENSION_RELOAD_BROADCAST_CHANNEL, EXTENSION_TERMINATE_BROADCAST_CHANNEL } from 'vs/platform/extensions/common/extensionHost';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { ILifecycleService, WillShutdownEvent } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
@@ -38,6 +36,7 @@ import { withNullAsUndefined } from 'vs/base/common/types';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { parseExtensionDevOptions } from '../common/extensionDevOptions';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
import { IExtensionHostDebugService } from 'vs/workbench/services/extensions/common/extensionHostDebug';
|
||||
|
||||
export interface IExtensionHostStarter {
|
||||
readonly onCrashed: Event<[number, string | null]>;
|
||||
@@ -77,12 +76,12 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter {
|
||||
@INotificationService private readonly _notificationService: INotificationService,
|
||||
@IWindowsService private readonly _windowsService: IWindowsService,
|
||||
@IWindowService private readonly _windowService: IWindowService,
|
||||
@IBroadcastService private readonly _broadcastService: IBroadcastService,
|
||||
@ILifecycleService private readonly _lifecycleService: ILifecycleService,
|
||||
@IEnvironmentService private readonly _environmentService: IEnvironmentService,
|
||||
@ITelemetryService private readonly _telemetryService: ITelemetryService,
|
||||
@ILogService private readonly _logService: ILogService,
|
||||
@ILabelService private readonly _labelService: ILabelService
|
||||
@ILabelService private readonly _labelService: ILabelService,
|
||||
@IExtensionHostDebugService private readonly _extensionHostDebugService: IExtensionHostDebugService
|
||||
) {
|
||||
const devOpts = parseExtensionDevOptions(this._environmentService);
|
||||
this._isExtensionDevHost = devOpts.isExtensionDevHost;
|
||||
@@ -102,7 +101,16 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter {
|
||||
this._toDispose.push(this._onCrashed);
|
||||
this._toDispose.push(this._lifecycleService.onWillShutdown(e => this._onWillShutdown(e)));
|
||||
this._toDispose.push(this._lifecycleService.onShutdown(reason => this.terminate()));
|
||||
this._toDispose.push(this._broadcastService.onBroadcast(b => this._onBroadcast(b)));
|
||||
this._toDispose.push(this._extensionHostDebugService.onClose(resource => {
|
||||
if (this._isExtensionDevHost && isEqual(resource, this._environmentService.extensionDevelopmentLocationURI)) {
|
||||
this._windowService.closeWindow();
|
||||
}
|
||||
}));
|
||||
this._toDispose.push(this._extensionHostDebugService.onReload(resource => {
|
||||
if (this._isExtensionDevHost && isEqual(resource, this._environmentService.extensionDevelopmentLocationURI)) {
|
||||
this._windowService.reloadWindow();
|
||||
}
|
||||
}));
|
||||
|
||||
const globalExitListener = () => this.terminate();
|
||||
process.once('exit', globalExitListener);
|
||||
@@ -115,24 +123,6 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter {
|
||||
this.terminate();
|
||||
}
|
||||
|
||||
private _onBroadcast(broadcast: IBroadcast): void {
|
||||
|
||||
// Close Ext Host Window Request
|
||||
if (broadcast.channel === EXTENSION_CLOSE_EXTHOST_BROADCAST_CHANNEL && this._isExtensionDevHost) {
|
||||
const extensionLocations = broadcast.payload as string[];
|
||||
if (Array.isArray(extensionLocations) && extensionLocations.some(uriString => isEqual(this._environmentService.extensionDevelopmentLocationURI, URI.parse(uriString)))) {
|
||||
this._windowService.closeWindow();
|
||||
}
|
||||
}
|
||||
|
||||
if (broadcast.channel === EXTENSION_RELOAD_BROADCAST_CHANNEL && this._isExtensionDevHost) {
|
||||
const extensionPaths = broadcast.payload as string[];
|
||||
if (Array.isArray(extensionPaths) && extensionPaths.some(uriString => isEqual(this._environmentService.extensionDevelopmentLocationURI, URI.parse(uriString)))) {
|
||||
this._windowService.reloadWindow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public start(): Promise<IMessagePassingProtocol> | null {
|
||||
if (this._terminating) {
|
||||
// .terminate() was called
|
||||
@@ -230,14 +220,8 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter {
|
||||
this._extensionHostProcess.on('exit', (code: number, signal: string) => this._onExtHostProcessExit(code, signal));
|
||||
|
||||
// Notify debugger that we are ready to attach to the process if we run a development extension
|
||||
if (this._isExtensionDevHost && portData.actual && this._isExtensionDevDebug) {
|
||||
this._broadcastService.broadcast({
|
||||
channel: EXTENSION_ATTACH_BROADCAST_CHANNEL,
|
||||
payload: {
|
||||
debugId: this._environmentService.debugExtensionHost.debugId,
|
||||
port: portData.actual
|
||||
}
|
||||
});
|
||||
if (this._isExtensionDevHost && portData.actual && this._isExtensionDevDebug && this._environmentService.debugExtensionHost.debugId) {
|
||||
this._extensionHostDebugService.attachSession(this._environmentService.debugExtensionHost.debugId, portData.actual);
|
||||
}
|
||||
this._inspectPort = portData.actual;
|
||||
|
||||
@@ -445,14 +429,8 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter {
|
||||
}
|
||||
|
||||
// Broadcast to other windows if we are in development mode
|
||||
else if (!this._environmentService.isBuilt || this._isExtensionDevHost) {
|
||||
this._broadcastService.broadcast({
|
||||
channel: EXTENSION_LOG_BROADCAST_CHANNEL,
|
||||
payload: {
|
||||
logEntry: entry,
|
||||
debugId: this._environmentService.debugExtensionHost.debugId
|
||||
}
|
||||
});
|
||||
else if (this._environmentService.debugExtensionHost.debugId && (!this._environmentService.isBuilt || this._isExtensionDevHost)) {
|
||||
this._extensionHostDebugService.logToSession(this._environmentService.debugExtensionHost.debugId, entry);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -557,14 +535,8 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter {
|
||||
|
||||
// If the extension development host was started without debugger attached we need
|
||||
// to communicate this back to the main side to terminate the debug session
|
||||
if (this._isExtensionDevHost && !this._isExtensionDevTestFromCli && !this._isExtensionDevDebug) {
|
||||
this._broadcastService.broadcast({
|
||||
channel: EXTENSION_TERMINATE_BROADCAST_CHANNEL,
|
||||
payload: {
|
||||
debugId: this._environmentService.debugExtensionHost.debugId
|
||||
}
|
||||
});
|
||||
|
||||
if (this._isExtensionDevHost && !this._isExtensionDevTestFromCli && !this._isExtensionDevDebug && this._environmentService.debugExtensionHost.debugId) {
|
||||
this._extensionHostDebugService.terminateSession(this._environmentService.debugExtensionHost.debugId);
|
||||
event.join(timeout(100 /* wait a bit for IPC to get delivered */));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { IWindowService } from 'vs/platform/windows/common/windows';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { IExtensionHostDebugService } from 'vs/workbench/services/extensions/common/extensionHostDebug';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IRemoteConsoleLog } from 'vs/base/common/console';
|
||||
import { ipcRenderer as ipc } from 'electron';
|
||||
|
||||
interface IReloadBroadcast {
|
||||
type: 'vscode:extensionReload';
|
||||
resource: string;
|
||||
}
|
||||
|
||||
interface IAttachSessionBroadcast {
|
||||
type: 'vscode:extensionAttach';
|
||||
id: string;
|
||||
port: number;
|
||||
}
|
||||
|
||||
interface ICloseBroadcast {
|
||||
type: 'vscode:extensionCloseExtensionHost';
|
||||
resource: string;
|
||||
}
|
||||
|
||||
interface ILogToSessionBroadcast {
|
||||
type: 'vscode:extensionLog';
|
||||
id: string;
|
||||
log: IRemoteConsoleLog;
|
||||
}
|
||||
|
||||
interface ITerminateSessionBroadcast {
|
||||
type: 'vscode:extensionTerminate';
|
||||
id: string;
|
||||
}
|
||||
|
||||
const CHANNEL = 'vscode:extensionHostDebug';
|
||||
|
||||
class ExtensionHostDebugService implements IExtensionHostDebugService {
|
||||
_serviceBrand: any;
|
||||
|
||||
private windowId: number;
|
||||
private readonly _onReload = new Emitter<URI>();
|
||||
private readonly _onClose = new Emitter<URI>();
|
||||
private readonly _onAttachSession = new Emitter<{ id: string, port: number }>();
|
||||
private readonly _onLogToSession = new Emitter<{ id: string, log: IRemoteConsoleLog }>();
|
||||
private readonly _onTerminateSession = new Emitter<string>();
|
||||
|
||||
constructor(
|
||||
@IWindowService readonly windowService: IWindowService,
|
||||
) {
|
||||
this.windowId = windowService.getCurrentWindowId();
|
||||
|
||||
ipc.on(CHANNEL, (_: unknown, broadcast: IReloadBroadcast | ICloseBroadcast | IAttachSessionBroadcast | ILogToSessionBroadcast | ITerminateSessionBroadcast) => {
|
||||
if (broadcast.type === 'vscode:extensionReload') {
|
||||
this._onReload.fire(URI.parse(broadcast.resource));
|
||||
}
|
||||
if (broadcast.type === 'vscode:extensionCloseExtensionHost') {
|
||||
this._onClose.fire(URI.parse(broadcast.resource));
|
||||
}
|
||||
if (broadcast.type === 'vscode:extensionAttach') {
|
||||
this._onAttachSession.fire({ id: broadcast.id, port: broadcast.port });
|
||||
}
|
||||
if (broadcast.type === 'vscode:extensionLog') {
|
||||
this._onLogToSession.fire({ id: broadcast.id, log: broadcast.log });
|
||||
}
|
||||
if (broadcast.type === 'vscode:extensionTerminate') {
|
||||
this._onTerminateSession.fire(broadcast.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
reload(resource: URI): void {
|
||||
ipc.send(CHANNEL, this.windowId, <IReloadBroadcast>{
|
||||
type: 'vscode:extensionReload',
|
||||
resource: resource.toString()
|
||||
});
|
||||
}
|
||||
|
||||
get onReload(): Event<URI> {
|
||||
return this._onReload.event;
|
||||
}
|
||||
|
||||
close(resource: URI): void {
|
||||
ipc.send(CHANNEL, this.windowId, <ICloseBroadcast>{
|
||||
type: 'vscode:extensionCloseExtensionHost',
|
||||
resource: resource.toString()
|
||||
});
|
||||
}
|
||||
|
||||
get onClose(): Event<URI> {
|
||||
return this._onClose.event;
|
||||
}
|
||||
|
||||
attachSession(id: string, port: number): void {
|
||||
ipc.send(CHANNEL, this.windowId, <IAttachSessionBroadcast>{
|
||||
type: 'vscode:extensionAttach',
|
||||
id,
|
||||
port
|
||||
});
|
||||
}
|
||||
|
||||
get onAttachSession(): Event<{ id: string, port: number }> {
|
||||
return this._onAttachSession.event;
|
||||
}
|
||||
|
||||
logToSession(id: string, log: IRemoteConsoleLog): void {
|
||||
ipc.send(CHANNEL, this.windowId, <ILogToSessionBroadcast>{
|
||||
type: 'vscode:extensionLog',
|
||||
id,
|
||||
log
|
||||
});
|
||||
}
|
||||
|
||||
get onLogToSession(): Event<{ id: string, log: IRemoteConsoleLog }> {
|
||||
return this._onLogToSession.event;
|
||||
}
|
||||
|
||||
terminateSession(id: string): void {
|
||||
ipc.send(CHANNEL, this.windowId, <ITerminateSessionBroadcast>{
|
||||
type: 'vscode:extensionTerminate',
|
||||
id
|
||||
});
|
||||
}
|
||||
|
||||
get onTerminateSession(): Event<string> {
|
||||
return this._onTerminateSession.event;
|
||||
}
|
||||
}
|
||||
|
||||
registerSingleton(IExtensionHostDebugService, ExtensionHostDebugService, true);
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import { Profile, ProfileNode } from 'v8-inspect-profiler';
|
||||
import { TernarySearchTree } from 'vs/base/common/map';
|
||||
import { realpathSync } from 'vs/base/node/extfs';
|
||||
import { realpathSync } from 'vs/base/node/extpath';
|
||||
import { IExtensionHostProfile, IExtensionService, ProfileSegmentId, ProfileSession } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { withNullAsUndefined } from 'vs/base/common/types';
|
||||
|
||||
@@ -0,0 +1,215 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Event, EventMultiplexer } from 'vs/base/common/event';
|
||||
import {
|
||||
IExtensionManagementService, ILocalExtension, IGalleryExtension, InstallExtensionEvent, DidInstallExtensionEvent, IExtensionIdentifier, DidUninstallExtensionEvent, IReportedExtension, IGalleryMetadata,
|
||||
IExtensionManagementServerService, IExtensionManagementServer, IExtensionGalleryService
|
||||
} from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { flatten } from 'vs/base/common/arrays';
|
||||
import { ExtensionType, IExtensionManifest, isLanguagePackExtension } from 'vs/platform/extensions/common/extensions';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { getManifest } from 'vs/platform/extensionManagement/node/extensionManagementUtil';
|
||||
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
||||
import { localize } from 'vs/nls';
|
||||
import { isUIExtension } from 'vs/workbench/services/extensions/node/extensionsUtil';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||
|
||||
export class MultiExtensionManagementService extends Disposable implements IExtensionManagementService {
|
||||
|
||||
_serviceBrand: any;
|
||||
|
||||
readonly onInstallExtension: Event<InstallExtensionEvent>;
|
||||
readonly onDidInstallExtension: Event<DidInstallExtensionEvent>;
|
||||
readonly onUninstallExtension: Event<IExtensionIdentifier>;
|
||||
readonly onDidUninstallExtension: Event<DidUninstallExtensionEvent>;
|
||||
|
||||
private readonly servers: IExtensionManagementServer[];
|
||||
|
||||
constructor(
|
||||
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
|
||||
@IExtensionGalleryService private readonly extensionGalleryService: IExtensionGalleryService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
@IRemoteAgentService private readonly remoteAgentService: IRemoteAgentService
|
||||
) {
|
||||
super();
|
||||
this.servers = this.extensionManagementServerService.remoteExtensionManagementServer ? [this.extensionManagementServerService.localExtensionManagementServer, this.extensionManagementServerService.remoteExtensionManagementServer] : [this.extensionManagementServerService.localExtensionManagementServer];
|
||||
|
||||
this.onInstallExtension = this._register(this.servers.reduce((emitter: EventMultiplexer<InstallExtensionEvent>, server) => { emitter.add(server.extensionManagementService.onInstallExtension); return emitter; }, new EventMultiplexer<InstallExtensionEvent>())).event;
|
||||
this.onDidInstallExtension = this._register(this.servers.reduce((emitter: EventMultiplexer<DidInstallExtensionEvent>, server) => { emitter.add(server.extensionManagementService.onDidInstallExtension); return emitter; }, new EventMultiplexer<DidInstallExtensionEvent>())).event;
|
||||
this.onUninstallExtension = this._register(this.servers.reduce((emitter: EventMultiplexer<IExtensionIdentifier>, server) => { emitter.add(server.extensionManagementService.onUninstallExtension); return emitter; }, new EventMultiplexer<IExtensionIdentifier>())).event;
|
||||
this.onDidUninstallExtension = this._register(this.servers.reduce((emitter: EventMultiplexer<DidUninstallExtensionEvent>, server) => { emitter.add(server.extensionManagementService.onDidUninstallExtension); return emitter; }, new EventMultiplexer<DidUninstallExtensionEvent>())).event;
|
||||
}
|
||||
|
||||
getInstalled(type?: ExtensionType): Promise<ILocalExtension[]> {
|
||||
return Promise.all(this.servers.map(({ extensionManagementService }) => extensionManagementService.getInstalled(type)))
|
||||
.then(result => flatten(result));
|
||||
}
|
||||
|
||||
async uninstall(extension: ILocalExtension, force?: boolean): Promise<void> {
|
||||
if (this.extensionManagementServerService.remoteExtensionManagementServer) {
|
||||
const server = this.getServer(extension);
|
||||
if (!server) {
|
||||
return Promise.reject(`Invalid location ${extension.location.toString()}`);
|
||||
}
|
||||
const syncExtensions = await this.hasToSyncExtensions();
|
||||
if (syncExtensions || isLanguagePackExtension(extension.manifest)) {
|
||||
return this.uninstallEverywhere(extension, force);
|
||||
}
|
||||
return this.uninstallInServer(extension, server, force);
|
||||
}
|
||||
return this.extensionManagementServerService.localExtensionManagementServer.extensionManagementService.uninstall(extension, force);
|
||||
}
|
||||
|
||||
private async uninstallEverywhere(extension: ILocalExtension, force?: boolean): Promise<void> {
|
||||
const server = this.getServer(extension);
|
||||
if (!server) {
|
||||
return Promise.reject(`Invalid location ${extension.location.toString()}`);
|
||||
}
|
||||
const promise = server.extensionManagementService.uninstall(extension);
|
||||
const anotherServer: IExtensionManagementServer = server === this.extensionManagementServerService.localExtensionManagementServer ? this.extensionManagementServerService.remoteExtensionManagementServer! : this.extensionManagementServerService.localExtensionManagementServer;
|
||||
const installed = await anotherServer.extensionManagementService.getInstalled(ExtensionType.User);
|
||||
extension = installed.filter(i => areSameExtensions(i.identifier, extension.identifier))[0];
|
||||
if (extension) {
|
||||
await anotherServer.extensionManagementService.uninstall(extension);
|
||||
}
|
||||
return promise;
|
||||
}
|
||||
|
||||
private async uninstallInServer(extension: ILocalExtension, server: IExtensionManagementServer, force?: boolean): Promise<void> {
|
||||
if (server === this.extensionManagementServerService.localExtensionManagementServer) {
|
||||
const installedExtensions = await this.extensionManagementServerService.remoteExtensionManagementServer!.extensionManagementService.getInstalled(ExtensionType.User);
|
||||
const dependentNonUIExtensions = installedExtensions.filter(i => !isUIExtension(i.manifest, this.configurationService)
|
||||
&& i.manifest.extensionDependencies && i.manifest.extensionDependencies.some(id => areSameExtensions({ id }, extension.identifier)));
|
||||
if (dependentNonUIExtensions.length) {
|
||||
return Promise.reject(new Error(this.getDependentsErrorMessage(extension, dependentNonUIExtensions)));
|
||||
}
|
||||
}
|
||||
return server.extensionManagementService.uninstall(extension, force);
|
||||
}
|
||||
|
||||
private getDependentsErrorMessage(extension: ILocalExtension, dependents: ILocalExtension[]): string {
|
||||
if (dependents.length === 1) {
|
||||
return localize('singleDependentError', "Cannot uninstall extension '{0}'. Extension '{1}' depends on this.",
|
||||
extension.manifest.displayName || extension.manifest.name, dependents[0].manifest.displayName || dependents[0].manifest.name);
|
||||
}
|
||||
if (dependents.length === 2) {
|
||||
return localize('twoDependentsError', "Cannot uninstall extension '{0}'. Extensions '{1}' and '{2}' depend on this.",
|
||||
extension.manifest.displayName || extension.manifest.name, dependents[0].manifest.displayName || dependents[0].manifest.name, dependents[1].manifest.displayName || dependents[1].manifest.name);
|
||||
}
|
||||
return localize('multipleDependentsError', "Cannot uninstall extension '{0}'. Extensions '{1}', '{2}' and others depend on this.",
|
||||
extension.manifest.displayName || extension.manifest.name, dependents[0].manifest.displayName || dependents[0].manifest.name, dependents[1].manifest.displayName || dependents[1].manifest.name);
|
||||
|
||||
}
|
||||
|
||||
reinstallFromGallery(extension: ILocalExtension): Promise<void> {
|
||||
const server = this.getServer(extension);
|
||||
if (server) {
|
||||
return server.extensionManagementService.reinstallFromGallery(extension);
|
||||
}
|
||||
return Promise.reject(`Invalid location ${extension.location.toString()}`);
|
||||
}
|
||||
|
||||
updateMetadata(extension: ILocalExtension, metadata: IGalleryMetadata): Promise<ILocalExtension> {
|
||||
const server = this.getServer(extension);
|
||||
if (server) {
|
||||
return server.extensionManagementService.updateMetadata(extension, metadata);
|
||||
}
|
||||
return Promise.reject(`Invalid location ${extension.location.toString()}`);
|
||||
}
|
||||
|
||||
zip(extension: ILocalExtension): Promise<URI> {
|
||||
throw new Error('Not Supported');
|
||||
}
|
||||
|
||||
unzip(zipLocation: URI, type: ExtensionType): Promise<IExtensionIdentifier> {
|
||||
return Promise.all(this.servers.map(({ extensionManagementService }) => extensionManagementService.unzip(zipLocation, type))).then(([extensionIdentifier]) => extensionIdentifier);
|
||||
}
|
||||
|
||||
async install(vsix: URI): Promise<IExtensionIdentifier> {
|
||||
if (this.extensionManagementServerService.remoteExtensionManagementServer) {
|
||||
const syncExtensions = await this.hasToSyncExtensions();
|
||||
const manifest = await getManifest(vsix.fsPath);
|
||||
if (syncExtensions || isLanguagePackExtension(manifest)) {
|
||||
// Install on both servers
|
||||
const [extensionIdentifier] = await Promise.all(this.servers.map(server => server.extensionManagementService.install(vsix)));
|
||||
return extensionIdentifier;
|
||||
}
|
||||
if (isUIExtension(manifest, this.configurationService)) {
|
||||
// Install only on local server
|
||||
return this.extensionManagementServerService.localExtensionManagementServer.extensionManagementService.install(vsix);
|
||||
}
|
||||
// Install only on remote server
|
||||
const promise = this.extensionManagementServerService.remoteExtensionManagementServer.extensionManagementService.install(vsix);
|
||||
// Install UI Dependencies on local server
|
||||
await this.installUIDependencies(manifest);
|
||||
return promise;
|
||||
}
|
||||
return this.extensionManagementServerService.localExtensionManagementServer.extensionManagementService.install(vsix);
|
||||
}
|
||||
|
||||
async installFromGallery(gallery: IGalleryExtension): Promise<void> {
|
||||
if (this.extensionManagementServerService.remoteExtensionManagementServer) {
|
||||
const [manifest, syncExtensions] = await Promise.all([this.extensionGalleryService.getManifest(gallery, CancellationToken.None), this.hasToSyncExtensions()]);
|
||||
if (manifest) {
|
||||
if (syncExtensions || isLanguagePackExtension(manifest)) {
|
||||
// Install on both servers
|
||||
return Promise.all(this.servers.map(server => server.extensionManagementService.installFromGallery(gallery))).then(() => undefined);
|
||||
}
|
||||
if (isUIExtension(manifest, this.configurationService)) {
|
||||
// Install only on local server
|
||||
return this.extensionManagementServerService.localExtensionManagementServer.extensionManagementService.installFromGallery(gallery);
|
||||
}
|
||||
// Install only on remote server
|
||||
const promise = this.extensionManagementServerService.remoteExtensionManagementServer.extensionManagementService.installFromGallery(gallery);
|
||||
// Install UI Dependencies on local server
|
||||
await this.installUIDependencies(manifest);
|
||||
return promise;
|
||||
} else {
|
||||
return Promise.reject(localize('Manifest is not found', "Installing Extension {0} failed: Manifest is not found.", gallery.displayName || gallery.name));
|
||||
}
|
||||
}
|
||||
return this.extensionManagementServerService.localExtensionManagementServer.extensionManagementService.installFromGallery(gallery);
|
||||
}
|
||||
|
||||
private async installUIDependencies(manifest: IExtensionManifest): Promise<void> {
|
||||
if (manifest.extensionDependencies && manifest.extensionDependencies.length) {
|
||||
const dependencies = await this.extensionGalleryService.loadAllDependencies(manifest.extensionDependencies.map(id => ({ id })), CancellationToken.None);
|
||||
if (dependencies.length) {
|
||||
await Promise.all(dependencies.map(async d => {
|
||||
const manifest = await this.extensionGalleryService.getManifest(d, CancellationToken.None);
|
||||
if (manifest && isUIExtension(manifest, this.configurationService)) {
|
||||
await this.extensionManagementServerService.localExtensionManagementServer.extensionManagementService.installFromGallery(d);
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getExtensionsReport(): Promise<IReportedExtension[]> {
|
||||
return this.extensionManagementServerService.localExtensionManagementServer.extensionManagementService.getExtensionsReport();
|
||||
}
|
||||
|
||||
private getServer(extension: ILocalExtension): IExtensionManagementServer | null {
|
||||
return this.extensionManagementServerService.getExtensionManagementServer(extension.location);
|
||||
}
|
||||
|
||||
private async hasToSyncExtensions(): Promise<boolean> {
|
||||
if (!this.extensionManagementServerService.remoteExtensionManagementServer) {
|
||||
return false;
|
||||
}
|
||||
const remoteEnv = await this.remoteAgentService.getEnvironment();
|
||||
if (!remoteEnv) {
|
||||
return false;
|
||||
}
|
||||
return remoteEnv.syncExtensions;
|
||||
}
|
||||
}
|
||||
|
||||
registerSingleton(IExtensionManagementService, MultiExtensionManagementService);
|
||||
Reference in New Issue
Block a user