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

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

- Download locally if installing extension fails in remote
上级 b2ff724d
...@@ -4,12 +4,14 @@ ...@@ -4,12 +4,14 @@
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc'; 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 { Event } from 'vs/base/common/event';
import { URI, UriComponents } from 'vs/base/common/uri'; import { URI, UriComponents } from 'vs/base/common/uri';
import { IURITransformer, DefaultURITransformer, transformAndReviveIncomingURIs } from 'vs/base/common/uriIpc'; import { IURITransformer, DefaultURITransformer, transformAndReviveIncomingURIs } from 'vs/base/common/uriIpc';
import { cloneAndChange } from 'vs/base/common/objects'; import { cloneAndChange } from 'vs/base/common/objects';
import { ExtensionType } from 'vs/platform/extensions/common/extensions'; 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 { function transformIncomingURI(uri: UriComponents, transformer: IURITransformer | null): URI {
return URI.revive(transformer ? transformer.transformIncoming(uri) : uri); return URI.revive(transformer ? transformer.transformIncoming(uri) : uri);
...@@ -78,7 +80,12 @@ export class ExtensionManagementChannelClient implements IExtensionManagementSer ...@@ -78,7 +80,12 @@ export class ExtensionManagementChannelClient implements IExtensionManagementSer
_serviceBrand: any; _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 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 })); } 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 ...@@ -97,8 +104,25 @@ export class ExtensionManagementChannelClient implements IExtensionManagementSer
return Promise.resolve(this.channel.call('install', [vsix])); return Promise.resolve(this.channel.call('install', [vsix]));
} }
installFromGallery(extension: IGalleryExtension): Promise<void> { async installFromGallery(extension: IGalleryExtension): Promise<void> {
return Promise.resolve(this.channel.call('installFromGallery', [extension])); 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> { uninstall(extension: ILocalExtension, force = false): Promise<void> {
......
...@@ -130,7 +130,7 @@ export class ExtensionContainers extends Disposable { ...@@ -130,7 +130,7 @@ export class ExtensionContainers extends Disposable {
for (const container of this.containers) { for (const container of this.containers) {
if (extension && container.extension) { if (extension && container.extension) {
if (areSameExtensions(container.extension.identifier, extension.identifier)) { 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; container.extension = extension;
} else if (container.updateWhenCounterExtensionChanges) { } else if (container.updateWhenCounterExtensionChanges) {
container.update(); container.update();
......
...@@ -217,7 +217,7 @@ export class InstallAction extends ExtensionAction { ...@@ -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)); 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); const runningExtension = await this.getRunningExtension(extension.local);
if (runningExtension) { if (runningExtension) {
const colorThemes = await this.workbenchThemeService.getColorThemes(); const colorThemes = await this.workbenchThemeService.getColorThemes();
...@@ -237,7 +237,7 @@ export class InstallAction extends ExtensionAction { ...@@ -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) return this.extensionsWorkbenchService.install(extension)
.then(null, err => { .then(null, err => {
if (!extension.gallery) { if (!extension.gallery) {
......
...@@ -309,13 +309,13 @@ class Extensions extends Disposable { ...@@ -309,13 +309,13 @@ class Extensions extends Disposable {
private readonly _onChange: Emitter<Extension | undefined> = new Emitter<Extension | undefined>(); private readonly _onChange: Emitter<Extension | undefined> = new Emitter<Extension | undefined>();
get onChange(): Event<Extension | undefined> { return this._onChange.event; } get onChange(): Event<Extension | undefined> { return this._onChange.event; }
private readonly stateProvider: IExtensionStateProvider<ExtensionState>;
private installing: Extension[] = []; private installing: Extension[] = [];
private uninstalling: Extension[] = []; private uninstalling: Extension[] = [];
private installed: Extension[] = []; private installed: Extension[] = [];
constructor( constructor(
private readonly server: IExtensionManagementServer, private readonly server: IExtensionManagementServer,
private readonly stateProvider: IExtensionStateProvider<ExtensionState>,
@IExtensionGalleryService private readonly galleryService: IExtensionGalleryService, @IExtensionGalleryService private readonly galleryService: IExtensionGalleryService,
@ITelemetryService private readonly telemetryService: ITelemetryService, @ITelemetryService private readonly telemetryService: ITelemetryService,
@ILogService private readonly logService: ILogService, @ILogService private readonly logService: ILogService,
...@@ -323,7 +323,6 @@ class Extensions extends Disposable { ...@@ -323,7 +323,6 @@ class Extensions extends Disposable {
@IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService @IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService
) { ) {
super(); super();
this.stateProvider = ext => this.getExtensionState(ext);
this._register(server.extensionManagementService.onInstallExtension(e => this.onInstallExtension(e))); this._register(server.extensionManagementService.onInstallExtension(e => this.onInstallExtension(e)));
this._register(server.extensionManagementService.onDidInstallExtension(e => this.onDidInstallExtension(e))); this._register(server.extensionManagementService.onDidInstallExtension(e => this.onDidInstallExtension(e)));
this._register(server.extensionManagementService.onUninstallExtension(e => this.onUninstallExtension(e))); this._register(server.extensionManagementService.onUninstallExtension(e => this.onUninstallExtension(e)));
...@@ -484,6 +483,7 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension ...@@ -484,6 +483,7 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
get onChange(): Event<IExtension | undefined> { return this._onChange.event; } get onChange(): Event<IExtension | undefined> { return this._onChange.event; }
private _extensionAllowedBadgeProviders: string[]; private _extensionAllowedBadgeProviders: string[];
private installing: IExtension[] = [];
constructor( constructor(
@IInstantiationService private readonly instantiationService: IInstantiationService, @IInstantiationService private readonly instantiationService: IInstantiationService,
...@@ -504,10 +504,10 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension ...@@ -504,10 +504,10 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
@IModeService private readonly modeService: IModeService @IModeService private readonly modeService: IModeService
) { ) {
super(); 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))); this._register(this.localExtensions.onChange(e => this._onChange.fire(e)));
if (this.extensionManagementServerService.remoteExtensionManagementServer) { 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))); this._register(this.remoteExtensions.onChange(e => this._onChange.fire(e)));
} else { } else {
this.remoteExtensions = null; this.remoteExtensions = null;
...@@ -672,6 +672,13 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension ...@@ -672,6 +672,13 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
} }
private getExtensionState(extension: Extension): ExtensionState { 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) { if (this.remoteExtensions) {
const state = this.remoteExtensions.getExtensionState(extension); const state = this.remoteExtensions.getExtensionState(extension);
if (state !== ExtensionState.Uninstalled) { if (state !== ExtensionState.Uninstalled) {
...@@ -771,8 +778,7 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension ...@@ -771,8 +778,7 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
} }
return this.installWithProgress(async () => { return this.installWithProgress(async () => {
const extensionService = extension.server && extension.local && !isLanguagePackExtension(extension.local.manifest) ? extension.server.extensionManagementService : this.extensionService; await this.installFromGallery(extension, gallery);
await extensionService.installFromGallery(gallery);
this.checkAndEnableDisabledDependencies(gallery.identifier); this.checkAndEnableDisabledDependencies(gallery.identifier);
return this.local.filter(local => areSameExtensions(local.identifier, gallery.identifier))[0]; return this.local.filter(local => areSameExtensions(local.identifier, gallery.identifier))[0];
}, gallery.displayName); }, gallery.displayName);
...@@ -790,8 +796,6 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension ...@@ -790,8 +796,6 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
if (!toUninstall) { if (!toUninstall) {
return Promise.reject(new Error('Missing local')); 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({ return this.progressService.withProgress({
location: ProgressLocation.Extensions, location: ProgressLocation.Extensions,
title: nls.localize('uninstallingExtension', 'Uninstalling extension....'), title: nls.localize('uninstallingExtension', 'Uninstalling extension....'),
...@@ -811,11 +815,10 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension ...@@ -811,11 +815,10 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
return this.galleryService.getCompatibleExtension(extension.gallery.identifier, version) return this.galleryService.getCompatibleExtension(extension.gallery.identifier, version)
.then(gallery => { .then(gallery => {
if (!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 () => { return this.installWithProgress(async () => {
const extensionService = extension.server && extension.local && !isLanguagePackExtension(extension.local.manifest) ? extension.server.extensionManagementService : this.extensionService; await this.installFromGallery(extension, gallery);
await extensionService.installFromGallery(gallery);
if (extension.latestVersion !== version) { if (extension.latestVersion !== version) {
this.ignoreAutoUpdate(new ExtensionIdentifierWithVersion(gallery.identifier, version)); this.ignoreAutoUpdate(new ExtensionIdentifierWithVersion(gallery.identifier, version));
} }
...@@ -847,6 +850,21 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension ...@@ -847,6 +850,21 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
}, () => installTask()); }, () => 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> { private checkAndEnableDisabledDependencies(extensionIdentifier: IExtensionIdentifier): Promise<void> {
const extension = this.local.filter(e => (e.local || e.gallery) && areSameExtensions(extensionIdentifier, e.identifier))[0]; const extension = this.local.filter(e => (e.local || e.gallery) && areSameExtensions(extensionIdentifier, e.identifier))[0];
if (extension) { if (extension) {
......
...@@ -78,7 +78,7 @@ suite('ExtensionsActions Test', () => { ...@@ -78,7 +78,7 @@ suite('ExtensionsActions Test', () => {
instantiationService.stub(IExtensionManagementServerService, new class extends ExtensionManagementServerService { instantiationService.stub(IExtensionManagementServerService, new class extends ExtensionManagementServerService {
private _localExtensionManagementServer: IExtensionManagementServer = { extensionManagementService: instantiationService.get(IExtensionManagementService), label: 'local', authority: 'vscode-local' }; private _localExtensionManagementServer: IExtensionManagementServer = { extensionManagementService: instantiationService.get(IExtensionManagementService), label: 'local', authority: 'vscode-local' };
constructor() { 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; } get localExtensionManagementServer(): IExtensionManagementServer { return this._localExtensionManagementServer; }
set localExtensionManagementServer(server: IExtensionManagementServer) { } set localExtensionManagementServer(server: IExtensionManagementServer) { }
......
...@@ -93,7 +93,7 @@ suite('ExtensionsListView Tests', () => { ...@@ -93,7 +93,7 @@ suite('ExtensionsListView Tests', () => {
instantiationService.stub(IExtensionManagementServerService, new class extends ExtensionManagementServerService { instantiationService.stub(IExtensionManagementServerService, new class extends ExtensionManagementServerService {
private _localExtensionManagementServer: IExtensionManagementServer = { extensionManagementService: instantiationService.get(IExtensionManagementService), label: 'local', authority: 'vscode-local' }; private _localExtensionManagementServer: IExtensionManagementServer = { extensionManagementService: instantiationService.get(IExtensionManagementService), label: 'local', authority: 'vscode-local' };
constructor() { 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; } get localExtensionManagementServer(): IExtensionManagementServer { return this._localExtensionManagementServer; }
set localExtensionManagementServer(server: IExtensionManagementServer) { } set localExtensionManagementServer(server: IExtensionManagementServer) { }
......
...@@ -6,13 +6,14 @@ ...@@ -6,13 +6,14 @@
import { localize } from 'vs/nls'; import { localize } from 'vs/nls';
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 { 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 { ExtensionManagementChannelClient } from 'vs/platform/extensionManagement/node/extensionManagementIpc';
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts'; import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
import { IChannel } from 'vs/base/parts/ipc/common/ipc'; import { IChannel } from 'vs/base/parts/ipc/common/ipc';
import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService'; import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { ILogService } from 'vs/platform/log/common/log';
const localExtensionManagementServerAuthority: string = 'vscode-local'; const localExtensionManagementServerAuthority: string = 'vscode-local';
...@@ -25,14 +26,16 @@ export class ExtensionManagementServerService implements IExtensionManagementSer ...@@ -25,14 +26,16 @@ export class ExtensionManagementServerService implements IExtensionManagementSer
constructor( constructor(
@ISharedProcessService sharedProcessService: ISharedProcessService, @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") }; this.localExtensionManagementServer = { extensionManagementService: localExtensionManagementService, authority: localExtensionManagementServerAuthority, label: localize('local', "Local") };
const remoteAgentConnection = remoteAgentService.getConnection(); const remoteAgentConnection = remoteAgentService.getConnection();
if (remoteAgentConnection) { 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") }; 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.
先完成此消息的编辑!
想要评论请 注册