diff --git a/src/vs/workbench/api/browser/mainThreadExtensionService.ts b/src/vs/workbench/api/browser/mainThreadExtensionService.ts index a77cf0e46e6..95d3b69e79d 100644 --- a/src/vs/workbench/api/browser/mainThreadExtensionService.ts +++ b/src/vs/workbench/api/browser/mainThreadExtensionService.ts @@ -197,9 +197,9 @@ class ExtensionHostProxy implements IExtensionHostProxy { resolveAuthority(remoteAuthority: string, resolveAttempt: number): Promise { return this._actual.$resolveAuthority(remoteAuthority, resolveAttempt); } - async getCanonicalURI(remoteAuthority: string, uri: URI): Promise { + async getCanonicalURI(remoteAuthority: string, uri: URI): Promise { const uriComponents = await this._actual.$getCanonicalURI(remoteAuthority, uri); - return URI.revive(uriComponents); + return (uriComponents ? URI.revive(uriComponents) : uriComponents); } startExtensionHost(enabledExtensionIds: ExtensionIdentifier[]): Promise { return this._actual.$startExtensionHost(enabledExtensionIds); diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 64f9f7de22a..73db462b209 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -1339,7 +1339,10 @@ export interface ExtHostSearchShape { export interface ExtHostExtensionServiceShape { $resolveAuthority(remoteAuthority: string, resolveAttempt: number): Promise; - $getCanonicalURI(remoteAuthority: string, uri: UriComponents): Promise; + /** + * Returns `null` if no resolver for `remoteAuthority` is found. + */ + $getCanonicalURI(remoteAuthority: string, uri: UriComponents): Promise; $startExtensionHost(enabledExtensionIds: ExtensionIdentifier[]): Promise; $extensionTestsExecute(): Promise; $extensionTestsExit(code: number): Promise; diff --git a/src/vs/workbench/api/common/extHostExtensionService.ts b/src/vs/workbench/api/common/extHostExtensionService.ts index 7d9e044afcc..3042ed465c3 100644 --- a/src/vs/workbench/api/common/extHostExtensionService.ts +++ b/src/vs/workbench/api/common/extHostExtensionService.ts @@ -753,12 +753,13 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme } } - public async $getCanonicalURI(remoteAuthority: string, uriComponents: UriComponents): Promise { + public async $getCanonicalURI(remoteAuthority: string, uriComponents: UriComponents): Promise { this._logService.info(`$getCanonicalURI invoked for authority (${getRemoteAuthorityPrefix(remoteAuthority)})`); - const { authorityPrefix, resolver } = await this._activateAndGetResolver(remoteAuthority); + const { resolver } = await this._activateAndGetResolver(remoteAuthority); if (!resolver) { - throw new Error(`Cannot get canonical URI because no remote extension is installed to resolve ${authorityPrefix}`); + // Return `null` if no resolver for `remoteAuthority` is found. + return null; } const uri = URI.revive(uriComponents); diff --git a/src/vs/workbench/services/extensions/common/abstractExtensionService.ts b/src/vs/workbench/services/extensions/common/abstractExtensionService.ts index 8888f363a01..e8cfe6e0f61 100644 --- a/src/vs/workbench/services/extensions/common/abstractExtensionService.ts +++ b/src/vs/workbench/services/extensions/common/abstractExtensionService.ts @@ -267,15 +267,6 @@ export abstract class AbstractExtensionService extends Disposable implements IEx protected abstract _pickRunningLocation(extensionId: ExtensionIdentifier, extensionKinds: ExtensionKind[], isInstalledLocally: boolean, isInstalledRemotely: boolean, preference: ExtensionRunningPreference): ExtensionRunningLocation | null; - protected _getExtensionHostManager(kind: ExtensionHostKind): IExtensionHostManager | null { - for (const extensionHostManager of this._extensionHostManagers) { - if (extensionHostManager.kind === kind) { - return extensionHostManager; - } - } - return null; - } - protected _getExtensionHostManagers(kind: ExtensionHostKind): IExtensionHostManager[] { return this._extensionHostManagers.filter(extHostManager => extHostManager.kind === kind); } diff --git a/src/vs/workbench/services/extensions/common/extensionHostManager.ts b/src/vs/workbench/services/extensions/common/extensionHostManager.ts index 1d041ff9057..911d5829102 100644 --- a/src/vs/workbench/services/extensions/common/extensionHostManager.ts +++ b/src/vs/workbench/services/extensions/common/extensionHostManager.ts @@ -45,7 +45,10 @@ export interface IExtensionHostManager { activationEventIsDone(activationEvent: string): boolean; getInspectPort(tryEnableInspector: boolean): Promise; resolveAuthority(remoteAuthority: string, resolveAttempt: number): Promise; - getCanonicalURI(remoteAuthority: string, uri: URI): Promise; + /** + * Returns `null` if no resolver for `remoteAuthority` is found. + */ + getCanonicalURI(remoteAuthority: string, uri: URI): Promise; start(enabledExtensionIds: ExtensionIdentifier[]): Promise; extensionTestsExecute(): Promise; extensionTestsSendExit(exitCode: number): Promise; @@ -383,18 +386,12 @@ class ExtensionHostManager extends Disposable implements IExtensionHostManager { } } - public async getCanonicalURI(remoteAuthority: string, uri: URI): Promise { - const authorityPlusIndex = remoteAuthority.indexOf('+'); - if (authorityPlusIndex === -1) { - // This authority does not use a resolver - return uri; - } + public async getCanonicalURI(remoteAuthority: string, uri: URI): Promise { const proxy = await this._proxy; if (!proxy) { throw new Error(`Cannot resolve canonical URI`); } - const result = await proxy.getCanonicalURI(remoteAuthority, uri); - return URI.revive(result); + return proxy.getCanonicalURI(remoteAuthority, uri); } public async start(enabledExtensionIds: ExtensionIdentifier[]): Promise { @@ -564,7 +561,7 @@ class LazyStartExtensionHostManager extends Disposable implements IExtensionHost } }; } - public async getCanonicalURI(remoteAuthority: string, uri: URI): Promise { + public async getCanonicalURI(remoteAuthority: string, uri: URI): Promise { await this._startCalled.wait(); if (this._actual) { return this._actual.getCanonicalURI(remoteAuthority, uri); diff --git a/src/vs/workbench/services/extensions/common/extensionHostProxy.ts b/src/vs/workbench/services/extensions/common/extensionHostProxy.ts index f3acf4420a0..d021dda0f0d 100644 --- a/src/vs/workbench/services/extensions/common/extensionHostProxy.ts +++ b/src/vs/workbench/services/extensions/common/extensionHostProxy.ts @@ -27,7 +27,10 @@ export type IResolveAuthorityResult = IResolveAuthorityErrorResult | IResolveAut export interface IExtensionHostProxy { resolveAuthority(remoteAuthority: string, resolveAttempt: number): Promise; - getCanonicalURI(remoteAuthority: string, uri: URI): Promise; + /** + * Returns `null` if no resolver for `remoteAuthority` is found. + */ + getCanonicalURI(remoteAuthority: string, uri: URI): Promise; startExtensionHost(enabledExtensionIds: ExtensionIdentifier[]): Promise; extensionTestsExecute(): Promise; extensionTestsExit(code: number): Promise; diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts index d5adedbc811..9e6b93c9fa0 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts @@ -49,6 +49,7 @@ import { CancellationToken } from 'vs/base/common/cancellation'; import { StopWatch } from 'vs/base/common/stopwatch'; import { isCI } from 'vs/base/common/platform'; import { IResolveAuthorityErrorResult } from 'vs/workbench/services/extensions/common/extensionHostProxy'; +import { URI } from 'vs/base/common/uri'; export class ExtensionService extends AbstractExtensionService implements IExtensionService { @@ -387,6 +388,32 @@ export class ExtensionService extends AbstractExtensionService implements IExten throw new RemoteAuthorityResolverError(bestErrorResult!.error.message, bestErrorResult!.error.code, bestErrorResult!.error.detail); } + private async _getCanonicalURI(remoteAuthority: string, uri: URI): Promise { + + const authorityPlusIndex = remoteAuthority.indexOf('+'); + if (authorityPlusIndex === -1) { + // This authority does not use a resolver + return uri; + } + + const localProcessExtensionHosts = this._getExtensionHostManagers(ExtensionHostKind.LocalProcess); + if (localProcessExtensionHosts.length === 0) { + // no local process extension hosts + throw new Error(`Cannot resolve canonical URI`); + } + + const results = await Promise.all(localProcessExtensionHosts.map(extHost => extHost.getCanonicalURI(remoteAuthority, uri))); + + for (const result of results) { + if (result) { + return result; + } + } + + // we can only reach this if there was no resolver extension that can return the cannonical uri + throw new Error(`Cannot get canonical URI because no extension is installed to resolve ${getRemoteAuthorityPrefix(remoteAuthority)}`); + } + private async _resolveAuthorityAgain(): Promise { const remoteAuthority = this._environmentService.remoteAuthority; if (!remoteAuthority) { @@ -421,12 +448,11 @@ export class ExtensionService extends AbstractExtensionService implements IExten // The current remote authority resolver cannot give the canonical URI for this URI return uri; } - const localProcessExtensionHost = this._getExtensionHostManager(ExtensionHostKind.LocalProcess)!; if (isCI) { this._logService.info(`Invoking getCanonicalURI for authority ${getRemoteAuthorityPrefix(remoteAuthority)}...`); } try { - return localProcessExtensionHost.getCanonicalURI(remoteAuthority, uri); + return this._getCanonicalURI(remoteAuthority, uri); } finally { if (isCI) { this._logService.info(`getCanonicalURI returned for authority ${getRemoteAuthorityPrefix(remoteAuthority)}.`);