提交 1af5b2a2 编写于 作者: S Sandeep Somavarapu

Fix #microsoft/vscode-remote-release/issues/231

- Download locally if installing extension fails in remote
上级 b2ff724d
......@@ -4,12 +4,14 @@
*--------------------------------------------------------------------------------------------*/
import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc';
import { IExtensionManagementService, ILocalExtension, InstallExtensionEvent, DidInstallExtensionEvent, IGalleryExtension, DidUninstallExtensionEvent, IExtensionIdentifier, IGalleryMetadata, IReportedExtension } from '../common/extensionManagement';
import { IExtensionManagementService, ILocalExtension, InstallExtensionEvent, DidInstallExtensionEvent, IGalleryExtension, DidUninstallExtensionEvent, IExtensionIdentifier, IGalleryMetadata, IReportedExtension, IExtensionGalleryService, InstallOperation } from '../common/extensionManagement';
import { Event } from 'vs/base/common/event';
import { URI, UriComponents } from 'vs/base/common/uri';
import { IURITransformer, DefaultURITransformer, transformAndReviveIncomingURIs } from 'vs/base/common/uriIpc';
import { cloneAndChange } from 'vs/base/common/objects';
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { ILogService } from 'vs/platform/log/common/log';
function transformIncomingURI(uri: UriComponents, transformer: IURITransformer | null): URI {
return URI.revive(transformer ? transformer.transformIncoming(uri) : uri);
......@@ -78,7 +80,12 @@ export class ExtensionManagementChannelClient implements IExtensionManagementSer
_serviceBrand: any;
constructor(private channel: IChannel) { }
constructor(
private readonly channel: IChannel,
private readonly remote: boolean,
private readonly galleryService: IExtensionGalleryService,
private readonly logService: ILogService
) { }
get onInstallExtension(): Event<InstallExtensionEvent> { return this.channel.listen('onInstallExtension'); }
get onDidInstallExtension(): Event<DidInstallExtensionEvent> { return Event.map(this.channel.listen<DidInstallExtensionEvent>('onDidInstallExtension'), i => ({ ...i, local: i.local ? transformIncomingExtension(i.local, null) : i.local })); }
......@@ -97,8 +104,25 @@ export class ExtensionManagementChannelClient implements IExtensionManagementSer
return Promise.resolve(this.channel.call('install', [vsix]));
}
installFromGallery(extension: IGalleryExtension): Promise<void> {
return Promise.resolve(this.channel.call('installFromGallery', [extension]));
async installFromGallery(extension: IGalleryExtension): Promise<void> {
try {
await Promise.resolve(this.channel.call('installFromGallery', [extension]));
} catch (error) {
if (this.remote) {
try {
const compatible = await this.galleryService.getCompatibleExtension(extension);
if (compatible) {
const installed = await this.getInstalled(ExtensionType.User);
const location = await this.galleryService.download(compatible, installed.filter(i => areSameExtensions(i.identifier, extension.identifier))[0] ? InstallOperation.Update : InstallOperation.Install);
await this.install(URI.file(location));
return;
}
} catch (e) {
this.logService.error(e);
}
}
throw error;
}
}
uninstall(extension: ILocalExtension, force = false): Promise<void> {
......
......@@ -130,7 +130,7 @@ export class ExtensionContainers extends Disposable {
for (const container of this.containers) {
if (extension && container.extension) {
if (areSameExtensions(container.extension.identifier, extension.identifier)) {
if (!container.extension.server || container.extension.server === extension.server) {
if (!container.extension.server || !extension.server || container.extension.server === extension.server) {
container.extension = extension;
} else if (container.updateWhenCounterExtensionChanges) {
container.update();
......
......@@ -217,7 +217,7 @@ export class InstallAction extends ExtensionAction {
alert(localize('installExtensionComplete', "Installing extension {0} is completed. Please reload Visual Studio Code to enable it.", this.extension.displayName));
if (extension.local) {
if (extension && extension.local) {
const runningExtension = await this.getRunningExtension(extension.local);
if (runningExtension) {
const colorThemes = await this.workbenchThemeService.getColorThemes();
......@@ -237,7 +237,7 @@ export class InstallAction extends ExtensionAction {
}
private install(extension: IExtension): Promise<IExtension> {
private install(extension: IExtension): Promise<IExtension | void> {
return this.extensionsWorkbenchService.install(extension)
.then(null, err => {
if (!extension.gallery) {
......
......@@ -309,13 +309,13 @@ class Extensions extends Disposable {
private readonly _onChange: Emitter<Extension | undefined> = new Emitter<Extension | undefined>();
get onChange(): Event<Extension | undefined> { return this._onChange.event; }
private readonly stateProvider: IExtensionStateProvider<ExtensionState>;
private installing: Extension[] = [];
private uninstalling: Extension[] = [];
private installed: Extension[] = [];
constructor(
private readonly server: IExtensionManagementServer,
private readonly stateProvider: IExtensionStateProvider<ExtensionState>,
@IExtensionGalleryService private readonly galleryService: IExtensionGalleryService,
@ITelemetryService private readonly telemetryService: ITelemetryService,
@ILogService private readonly logService: ILogService,
......@@ -323,7 +323,6 @@ class Extensions extends Disposable {
@IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService
) {
super();
this.stateProvider = ext => this.getExtensionState(ext);
this._register(server.extensionManagementService.onInstallExtension(e => this.onInstallExtension(e)));
this._register(server.extensionManagementService.onDidInstallExtension(e => this.onDidInstallExtension(e)));
this._register(server.extensionManagementService.onUninstallExtension(e => this.onUninstallExtension(e)));
......@@ -484,6 +483,7 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
get onChange(): Event<IExtension | undefined> { return this._onChange.event; }
private _extensionAllowedBadgeProviders: string[];
private installing: IExtension[] = [];
constructor(
@IInstantiationService private readonly instantiationService: IInstantiationService,
......@@ -504,10 +504,10 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
@IModeService private readonly modeService: IModeService
) {
super();
this.localExtensions = this._register(instantiationService.createInstance(Extensions, extensionManagementServerService.localExtensionManagementServer));
this.localExtensions = this._register(instantiationService.createInstance(Extensions, extensionManagementServerService.localExtensionManagementServer, ext => this.getExtensionState(ext)));
this._register(this.localExtensions.onChange(e => this._onChange.fire(e)));
if (this.extensionManagementServerService.remoteExtensionManagementServer) {
this.remoteExtensions = this._register(instantiationService.createInstance(Extensions, extensionManagementServerService.remoteExtensionManagementServer));
this.remoteExtensions = this._register(instantiationService.createInstance(Extensions, extensionManagementServerService.remoteExtensionManagementServer, ext => this.getExtensionState(ext)));
this._register(this.remoteExtensions.onChange(e => this._onChange.fire(e)));
} else {
this.remoteExtensions = null;
......@@ -672,6 +672,13 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
}
private getExtensionState(extension: Extension): ExtensionState {
const isInstalling = this.installing.some(i => areSameExtensions(i.identifier, extension.identifier));
if (extension.server) {
const state = (extension.server === this.extensionManagementServerService.localExtensionManagementServer ? this.localExtensions : this.remoteExtensions!).getExtensionState(extension);
return state === ExtensionState.Uninstalled && isInstalling ? ExtensionState.Installing : state;
} else if (isInstalling) {
return ExtensionState.Installing;
}
if (this.remoteExtensions) {
const state = this.remoteExtensions.getExtensionState(extension);
if (state !== ExtensionState.Uninstalled) {
......@@ -771,8 +778,7 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
}
return this.installWithProgress(async () => {
const extensionService = extension.server && extension.local && !isLanguagePackExtension(extension.local.manifest) ? extension.server.extensionManagementService : this.extensionService;
await extensionService.installFromGallery(gallery);
await this.installFromGallery(extension, gallery);
this.checkAndEnableDisabledDependencies(gallery.identifier);
return this.local.filter(local => areSameExtensions(local.identifier, gallery.identifier))[0];
}, gallery.displayName);
......@@ -790,8 +796,6 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
if (!toUninstall) {
return Promise.reject(new Error('Missing local'));
}
this.logService.info(`Requested uninstalling the extension ${extension.identifier.id} from window ${this.windowService.windowId}`);
return this.progressService.withProgress({
location: ProgressLocation.Extensions,
title: nls.localize('uninstallingExtension', 'Uninstalling extension....'),
......@@ -811,11 +815,10 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
return this.galleryService.getCompatibleExtension(extension.gallery.identifier, version)
.then(gallery => {
if (!gallery) {
return Promise.reject(new Error(nls.localize('incompatible', "Unable to install extension '{0}' with version '{1}' as it is not compatible with VS Code.", extension.gallery!.identifier.id, version)));
return Promise.reject(new Error(nls.localize('incompatible', "Unable to install extension '{0}' as it is not compatible with VS Code '{1}'.", extension.gallery!.identifier.id, version)));
}
return this.installWithProgress(async () => {
const extensionService = extension.server && extension.local && !isLanguagePackExtension(extension.local.manifest) ? extension.server.extensionManagementService : this.extensionService;
await extensionService.installFromGallery(gallery);
await this.installFromGallery(extension, gallery);
if (extension.latestVersion !== version) {
this.ignoreAutoUpdate(new ExtensionIdentifierWithVersion(gallery.identifier, version));
}
......@@ -847,6 +850,21 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
}, () => installTask());
}
private async installFromGallery(extension: IExtension, gallery: IGalleryExtension): Promise<void> {
this.installing.push(extension);
this._onChange.fire(extension);
try {
const extensionService = extension.server && extension.local && !isLanguagePackExtension(extension.local.manifest) ? extension.server.extensionManagementService : this.extensionService;
await extensionService.installFromGallery(gallery);
const ids: string[] | undefined = extension.identifier.uuid ? [extension.identifier.uuid] : undefined;
const names: string[] | undefined = extension.identifier.uuid ? undefined : [extension.identifier.id];
this.queryGallery({ names, ids, pageSize: 1 }, CancellationToken.None);
} finally {
this.installing = this.installing.filter(e => e !== extension);
this._onChange.fire(extension);
}
}
private checkAndEnableDisabledDependencies(extensionIdentifier: IExtensionIdentifier): Promise<void> {
const extension = this.local.filter(e => (e.local || e.gallery) && areSameExtensions(extensionIdentifier, e.identifier))[0];
if (extension) {
......
......@@ -78,7 +78,7 @@ suite('ExtensionsActions Test', () => {
instantiationService.stub(IExtensionManagementServerService, new class extends ExtensionManagementServerService {
private _localExtensionManagementServer: IExtensionManagementServer = { extensionManagementService: instantiationService.get(IExtensionManagementService), label: 'local', authority: 'vscode-local' };
constructor() {
super(instantiationService.get(ISharedProcessService), instantiationService.get(IRemoteAgentService));
super(instantiationService.get(ISharedProcessService), instantiationService.get(IRemoteAgentService), instantiationService.get(IExtensionGalleryService), instantiationService.get(ILogService));
}
get localExtensionManagementServer(): IExtensionManagementServer { return this._localExtensionManagementServer; }
set localExtensionManagementServer(server: IExtensionManagementServer) { }
......
......@@ -93,7 +93,7 @@ suite('ExtensionsListView Tests', () => {
instantiationService.stub(IExtensionManagementServerService, new class extends ExtensionManagementServerService {
private _localExtensionManagementServer: IExtensionManagementServer = { extensionManagementService: instantiationService.get(IExtensionManagementService), label: 'local', authority: 'vscode-local' };
constructor() {
super(instantiationService.get(ISharedProcessService), instantiationService.get(IRemoteAgentService));
super(instantiationService.get(ISharedProcessService), instantiationService.get(IRemoteAgentService), instantiationService.get(IExtensionGalleryService), instantiationService.get(ILogService));
}
get localExtensionManagementServer(): IExtensionManagementServer { return this._localExtensionManagementServer; }
set localExtensionManagementServer(server: IExtensionManagementServer) { }
......
......@@ -6,13 +6,14 @@
import { localize } from 'vs/nls';
import { Schemas } from 'vs/base/common/network';
import { URI } from 'vs/base/common/uri';
import { IExtensionManagementServer, IExtensionManagementServerService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { IExtensionManagementServer, IExtensionManagementServerService, IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { ExtensionManagementChannelClient } from 'vs/platform/extensionManagement/node/extensionManagementIpc';
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
import { IChannel } from 'vs/base/parts/ipc/common/ipc';
import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { ILogService } from 'vs/platform/log/common/log';
const localExtensionManagementServerAuthority: string = 'vscode-local';
......@@ -25,14 +26,16 @@ export class ExtensionManagementServerService implements IExtensionManagementSer
constructor(
@ISharedProcessService sharedProcessService: ISharedProcessService,
@IRemoteAgentService remoteAgentService: IRemoteAgentService
@IRemoteAgentService remoteAgentService: IRemoteAgentService,
@IExtensionGalleryService galleryService: IExtensionGalleryService,
@ILogService logService: ILogService
) {
const localExtensionManagementService = new ExtensionManagementChannelClient(sharedProcessService.getChannel('extensions'));
const localExtensionManagementService = new ExtensionManagementChannelClient(sharedProcessService.getChannel('extensions'), false, galleryService, logService);
this.localExtensionManagementServer = { extensionManagementService: localExtensionManagementService, authority: localExtensionManagementServerAuthority, label: localize('local', "Local") };
const remoteAgentConnection = remoteAgentService.getConnection();
if (remoteAgentConnection) {
const extensionManagementService = new ExtensionManagementChannelClient(remoteAgentConnection.getChannel<IChannel>('extensions'));
const extensionManagementService = new ExtensionManagementChannelClient(remoteAgentConnection.getChannel<IChannel>('extensions'), true, galleryService, logService);
this.remoteExtensionManagementServer = { authority: remoteAgentConnection.remoteAuthority, extensionManagementService, label: localize('remote', "Remote") };
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册