diff --git a/CHANGELOG.md b/CHANGELOG.md index fa0f5e683eb37..785f2cc6f65fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,8 @@ - [core] moved `NewWindowOptions` to `common/window.ts` [#10291](https://github.com/eclipse-theia/theia/pull/10291) - [ovsx-client] removed `fetchJson` method from `OVSXClient` [#10325](https://github.com/eclipse-theia/theia/pull/10325) - [callhierarchy, plugin-ext] Call hierarchy methods `getRootDefinition`, `$provideRootDefinition`, `provideRootDefinition`, and `prepareCallHierarchy` retyped to allow a return of an item or an array of items. [#10310](https://github.com/eclipse-theia/theia/pull/10310) +- [vsx-registry] removed `OVSXAsyncClient` [#10327](https://github.com/eclipse-theia/theia/pull/10327) +- [vsx-registry] updated `VSXEnvironment` from a class to an interface and symbol implemented in both `browser` and `node` [#10327](https://github.com/eclipse-theia/theia/pull/10327) ## v1.18.0 - 9/30/2021 diff --git a/dev-packages/ovsx-client/src/ovsx-client.ts b/dev-packages/ovsx-client/src/ovsx-client.ts index 685316a6bcd46..2d49873d29aa6 100644 --- a/dev-packages/ovsx-client/src/ovsx-client.ts +++ b/dev-packages/ovsx-client/src/ovsx-client.ts @@ -34,6 +34,7 @@ export interface OVSXClientOptions { apiVersion: string apiUrl: string } + export class OVSXClient { constructor(readonly options: OVSXClientOptions) { } diff --git a/packages/plugin-ext-vscode/src/node/plugin-vscode-cli-contribution.ts b/packages/plugin-ext-vscode/src/node/plugin-vscode-cli-contribution.ts index a16c8272aabf5..f23be990a5970 100644 --- a/packages/plugin-ext-vscode/src/node/plugin-vscode-cli-contribution.ts +++ b/packages/plugin-ext-vscode/src/node/plugin-vscode-cli-contribution.ts @@ -19,6 +19,7 @@ import { Argv, Arguments } from '@theia/core/shared/yargs'; import { CliContribution } from '@theia/core/lib/node/cli'; import { PluginHostEnvironmentVariable } from '@theia/plugin-ext/lib/common'; import { VSCODE_DEFAULT_API_VERSION } from '../common/plugin-vscode-types'; +import { Deferred } from '@theia/core/lib/common/promise-util'; /** * CLI Contribution allowing to override the VS Code API version which is returned by `vscode.version` API call. @@ -26,9 +27,17 @@ import { VSCODE_DEFAULT_API_VERSION } from '../common/plugin-vscode-types'; @injectable() export class PluginVsCodeCliContribution implements CliContribution, PluginHostEnvironmentVariable { + /** + * CLI argument name to define the supported VS Code API version. + */ static VSCODE_API_VERSION = 'vscode-api-version'; - protected vsCodeApiVersion: string | undefined; + protected vsCodeApiVersion?: string; + protected vsCodeApiVersionDeferred = new Deferred(); + + get vsCodeApiVersionPromise(): Promise { + return this.vsCodeApiVersionDeferred.promise; + } configure(conf: Argv): void { conf.option(PluginVsCodeCliContribution.VSCODE_API_VERSION, { @@ -40,11 +49,10 @@ export class PluginVsCodeCliContribution implements CliContribution, PluginHostE } setArguments(args: Arguments): void { - const arg = args[PluginVsCodeCliContribution.VSCODE_API_VERSION] as string; - if (arg) { - this.vsCodeApiVersion = arg; - this.process(process.env); - } + const arg = args[PluginVsCodeCliContribution.VSCODE_API_VERSION] as string | undefined; + this.vsCodeApiVersion = arg?.trim() || process.env['VSCODE_API_VERSION']?.trim() || VSCODE_DEFAULT_API_VERSION; + process.env['VSCODE_API_VERSION'] = this.vsCodeApiVersion; + this.vsCodeApiVersionDeferred.resolve(this.vsCodeApiVersion); } process(env: NodeJS.ProcessEnv): void { diff --git a/packages/vsx-registry/src/browser/vsx-extension.tsx b/packages/vsx-registry/src/browser/vsx-extension.tsx index a16b1dc65ba4e..baf870e13bdda 100644 --- a/packages/vsx-registry/src/browser/vsx-extension.tsx +++ b/packages/vsx-registry/src/browser/vsx-extension.tsx @@ -322,7 +322,7 @@ export class VSXExtension implements VSXExtensionData, TreeElement { * @returns the registry link for the given extension at the path. */ async getRegistryLink(path = ''): Promise { - const uri = await this.environment.getRegistryUri(); + const uri = new URI(await this.environment.getRegistryUri()); return uri.resolve('extension/' + this.id.replace('.', '/')).resolve(path); } diff --git a/packages/vsx-registry/src/browser/vsx-extensions-model.ts b/packages/vsx-registry/src/browser/vsx-extensions-model.ts index ba611fdc387f7..3fa521820032d 100644 --- a/packages/vsx-registry/src/browser/vsx-extensions-model.ts +++ b/packages/vsx-registry/src/browser/vsx-extensions-model.ts @@ -30,7 +30,7 @@ import { WorkspaceService } from '@theia/workspace/lib/browser'; import { RecommendedExtensions } from './recommended-extensions/recommended-extensions-preference-contribution'; import URI from '@theia/core/lib/common/uri'; import { VSXResponseError, VSXSearchParam } from '@theia/ovsx-client/lib/ovsx-types'; -import { OVSXAsyncClient } from './ovsx-async-client'; +import { OVSXClientProvider } from '../common/ovsx-client-provider'; @injectable() export class VSXExtensionsModel { @@ -38,8 +38,8 @@ export class VSXExtensionsModel { protected readonly onDidChangeEmitter = new Emitter(); readonly onDidChange = this.onDidChangeEmitter.event; - @inject(OVSXAsyncClient) - protected client: OVSXAsyncClient; + @inject(OVSXClientProvider) + protected clientProvider: OVSXClientProvider; @inject(HostedPluginSupport) protected readonly pluginSupport: HostedPluginSupport; @@ -63,7 +63,6 @@ export class VSXExtensionsModel { @postConstruct() protected async init(): Promise { - await this.client.ready; await Promise.all([ this.initInstalled(), this.initSearchResult(), @@ -167,14 +166,15 @@ export class VSXExtensionsModel { }, 150); protected doUpdateSearchResult(param: VSXSearchParam, token: CancellationToken): Promise { return this.doChange(async () => { - const result = await this.client.search(param); + const client = await this.clientProvider(); + const result = await client.search(param); if (token.isCancellationRequested) { return; } const searchResult = new Set(); for (const data of result.extensions) { const id = data.namespace.toLowerCase() + '.' + data.name.toLowerCase(); - const extension = this.client.getLatestCompatibleVersion(data); + const extension = client.getLatestCompatibleVersion(data); if (!extension) { continue; } @@ -260,7 +260,8 @@ export class VSXExtensionsModel { } if (extension.readmeUrl) { try { - const rawReadme = await this.client.fetchText(extension.readmeUrl); + const client = await this.clientProvider(); + const rawReadme = await client.fetchText(extension.readmeUrl); const readme = this.compileReadme(rawReadme); extension.update({ readme }); } catch (e) { @@ -292,7 +293,8 @@ export class VSXExtensionsModel { if (!this.shouldRefresh(extension)) { return extension; } - const data = await this.client.getLatestCompatibleExtensionVersion(id); + const client = await this.clientProvider(); + const data = await client.getLatestCompatibleExtensionVersion(id); if (!data) { return; } diff --git a/packages/vsx-registry/src/browser/vsx-registry-frontend-module.ts b/packages/vsx-registry/src/browser/vsx-registry-frontend-module.ts index 300de4549dbb7..efcdbb93e4b44 100644 --- a/packages/vsx-registry/src/browser/vsx-registry-frontend-module.ts +++ b/packages/vsx-registry/src/browser/vsx-registry-frontend-module.ts @@ -17,7 +17,9 @@ import '../../src/browser/style/index.css'; import { ContainerModule } from '@theia/core/shared/inversify'; -import { WidgetFactory, bindViewContribution, FrontendApplicationContribution, ViewContainerIdentifier, OpenHandler, WidgetManager } from '@theia/core/lib/browser'; +import { + WidgetFactory, bindViewContribution, FrontendApplicationContribution, ViewContainerIdentifier, OpenHandler, WidgetManager, WebSocketConnectionProvider +} from '@theia/core/lib/browser'; import { VSXExtensionsViewContainer } from './vsx-extensions-view-container'; import { VSXExtensionsContribution } from './vsx-extensions-contribution'; import { VSXExtensionsSearchBar } from './vsx-extensions-search-bar'; @@ -28,24 +30,20 @@ import { VSXExtensionFactory, VSXExtension, VSXExtensionOptions } from './vsx-ex import { VSXExtensionEditor } from './vsx-extension-editor'; import { VSXExtensionEditorManager } from './vsx-extension-editor-manager'; import { VSXExtensionsSourceOptions } from './vsx-extensions-source'; -import { VSXEnvironment } from '../common/vsx-environment'; import { VSXExtensionsSearchModel } from './vsx-extensions-search-model'; import { bindExtensionPreferences } from './recommended-extensions/recommended-extensions-preference-contribution'; import { bindPreferenceProviderOverrides } from './recommended-extensions/preference-provider-overrides'; -import { OVSXAsyncClient } from './ovsx-async-client'; +import { OVSXClientProvider, createOVSXClient } from '../common/ovsx-client-provider'; +import { VSXEnvironment, VSX_ENVIRONMENT_PATH } from '../common/vsx-environment'; export default new ContainerModule((bind, unbind) => { - bind(VSXEnvironment).toSelf().inSingletonScope(); - bind(OVSXAsyncClient).toDynamicValue(ctx => { - const vsxEnvironment = ctx.container.get(VSXEnvironment); - return new OVSXAsyncClient(Promise.all([ - vsxEnvironment.getVscodeApiVersion(), - vsxEnvironment.getRegistryApiUri() - ]).then(([apiVersion, apiUri]) => ({ - apiVersion, - apiUrl: apiUri.toString() - }))); + bind(OVSXClientProvider).toDynamicValue(ctx => { + const clientPromise = createOVSXClient(ctx.container.get(VSXEnvironment)); + return () => clientPromise; }).inSingletonScope(); + bind(VSXEnvironment).toDynamicValue( + ctx => WebSocketConnectionProvider.createProxy(ctx.container, VSX_ENVIRONMENT_PATH) + ).inSingletonScope(); bind(VSXExtension).toSelf(); bind(VSXExtensionFactory).toFactory(ctx => (option: VSXExtensionOptions) => { diff --git a/packages/vsx-registry/src/browser/ovsx-async-client.ts b/packages/vsx-registry/src/common/ovsx-client-provider.ts similarity index 51% rename from packages/vsx-registry/src/browser/ovsx-async-client.ts rename to packages/vsx-registry/src/common/ovsx-client-provider.ts index 56871769e873d..f85898dd56dfe 100644 --- a/packages/vsx-registry/src/browser/ovsx-async-client.ts +++ b/packages/vsx-registry/src/common/ovsx-client-provider.ts @@ -14,26 +14,16 @@ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 ********************************************************************************/ -import { OVSXClient, OVSXClientOptions } from '@theia/ovsx-client/lib'; +import { OVSXClient } from '@theia/ovsx-client'; +import { VSXEnvironment } from './vsx-environment'; -/** - * In some instances, the OVSXClient must be created asynchronously. This class - * makes it possible to get an un-initialized instance and wait for it to be ready. - */ -export class OVSXAsyncClient extends OVSXClient { +export const OVSXClientProvider = Symbol('OVSXClientProvider'); +export type OVSXClientProvider = () => Promise; - /** - * Resolves once the initial asynchronous options are resolved. - * - * Calling methods before this promise is resolved will throw errors. - */ - readonly ready: Promise; - - constructor(asyncOptions: Promise) { - super(undefined!); // hack: using methods at this point will fail. - this.ready = asyncOptions.then(options => { - (this.options as OVSXClientOptions) = options; - return this; - }); - } +export async function createOVSXClient(vsxEnvironment: VSXEnvironment): Promise { + const [apiVersion, apiUrl] = await Promise.all([ + vsxEnvironment.getVscodeApiVersion(), + vsxEnvironment.getRegistryApiUri() + ]); + return new OVSXClient({ apiVersion, apiUrl: apiUrl.toString() }); } diff --git a/packages/vsx-registry/src/common/vsx-environment.ts b/packages/vsx-registry/src/common/vsx-environment.ts new file mode 100644 index 0000000000000..25ae36e78d7c2 --- /dev/null +++ b/packages/vsx-registry/src/common/vsx-environment.ts @@ -0,0 +1,24 @@ +/******************************************************************************** + * Copyright (C) 2021 Ericsson and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the Eclipse + * Public License v. 2.0 are satisfied: GNU General Public License, version 2 + * with the GNU Classpath Exception which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + ********************************************************************************/ + +export const VSX_ENVIRONMENT_PATH = '/services/vsx-environment'; + +export const VSXEnvironment = Symbol('VSXEnvironment'); +export interface VSXEnvironment { + getRegistryUri(): Promise; + getRegistryApiUri(): Promise; + getVscodeApiVersion(): Promise; +} diff --git a/packages/vsx-registry/src/common/vsx-environment.tsx b/packages/vsx-registry/src/common/vsx-environment.tsx deleted file mode 100644 index 5f70f3d0d480d..0000000000000 --- a/packages/vsx-registry/src/common/vsx-environment.tsx +++ /dev/null @@ -1,51 +0,0 @@ -/******************************************************************************** - * Copyright (C) 2020 TypeFox and others. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0. - * - * This Source Code may also be made available under the following Secondary - * Licenses when the conditions for such availability set forth in the Eclipse - * Public License v. 2.0 are satisfied: GNU General Public License, version 2 - * with the GNU Classpath Exception which is available at - * https://www.gnu.org/software/classpath/license.html. - * - * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 - ********************************************************************************/ - -import { injectable, inject } from '@theia/core/shared/inversify'; -import { EnvVariablesServer } from '@theia/core/lib/common/env-variables'; -import URI from '@theia/core/lib/common/uri'; -import { VSCODE_DEFAULT_API_VERSION } from '@theia/plugin-ext-vscode/lib/common/plugin-vscode-types'; - -@injectable() -export class VSXEnvironment { - - @inject(EnvVariablesServer) - protected readonly environments: EnvVariablesServer; - - protected _registryUri: URI | undefined; - async getRegistryUri(): Promise { - if (!this._registryUri) { - const vsxRegistryUrl = await this.environments.getValue('VSX_REGISTRY_URL'); - this._registryUri = new URI(vsxRegistryUrl && vsxRegistryUrl.value || 'https://open-vsx.org'); - } - return this._registryUri; - } - - async getRegistryApiUri(): Promise { - const registryUri = await this.getRegistryUri(); - return registryUri.resolve('api'); - } - - protected _apiVersion: string | undefined; - async getVscodeApiVersion(): Promise { - if (!this._apiVersion) { - const apiVersion = await this.environments.getValue('VSCODE_API_VERSION'); - this._apiVersion = apiVersion?.value || VSCODE_DEFAULT_API_VERSION; - } - return this._apiVersion; - } - -} diff --git a/packages/vsx-registry/src/node/vsx-environment-impl.ts b/packages/vsx-registry/src/node/vsx-environment-impl.ts new file mode 100644 index 0000000000000..86dbb0d8792b7 --- /dev/null +++ b/packages/vsx-registry/src/node/vsx-environment-impl.ts @@ -0,0 +1,41 @@ +/******************************************************************************** + * Copyright (C) 2020 TypeFox and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the Eclipse + * Public License v. 2.0 are satisfied: GNU General Public License, version 2 + * with the GNU Classpath Exception which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + ********************************************************************************/ + +import { injectable, inject } from '@theia/core/shared/inversify'; +import URI from '@theia/core/lib/common/uri'; +import { PluginVsCodeCliContribution } from '@theia/plugin-ext-vscode/lib/node/plugin-vscode-cli-contribution'; +import { VSXEnvironment } from '../common/vsx-environment'; + +@injectable() +export class VSXEnvironmentImpl implements VSXEnvironment { + + protected _registryUri = new URI(process.env['VSX_REGISTRY_URL']?.trim() || 'https://open-vsx.org'); + + @inject(PluginVsCodeCliContribution) + protected readonly pluginVscodeCli: PluginVsCodeCliContribution; + + async getRegistryUri(): Promise { + return this._registryUri.toString(true); + } + + async getRegistryApiUri(): Promise { + return this._registryUri.resolve('api').toString(true); + } + + async getVscodeApiVersion(): Promise { + return this.pluginVscodeCli.vsCodeApiVersionPromise; + } +} diff --git a/packages/vsx-registry/src/node/vsx-extension-resolver.ts b/packages/vsx-registry/src/node/vsx-extension-resolver.ts index 029afe1470078..84cd5e939e635 100644 --- a/packages/vsx-registry/src/node/vsx-extension-resolver.ts +++ b/packages/vsx-registry/src/node/vsx-extension-resolver.ts @@ -23,13 +23,13 @@ import { injectable, inject } from '@theia/core/shared/inversify'; import URI from '@theia/core/lib/common/uri'; import { PluginDeployerResolver, PluginDeployerResolverContext } from '@theia/plugin-ext/lib/common/plugin-protocol'; import { VSXExtensionUri } from '../common/vsx-extension-uri'; -import { OVSXClient } from '@theia/ovsx-client/lib/ovsx-client'; +import { OVSXClientProvider } from '../common/ovsx-client-provider'; @injectable() export class VSXExtensionResolver implements PluginDeployerResolver { - @inject(OVSXClient) - protected client: OVSXClient; + @inject(OVSXClientProvider) + protected clientProvider: OVSXClientProvider; protected readonly downloadPath: string; @@ -49,7 +49,8 @@ export class VSXExtensionResolver implements PluginDeployerResolver { return; } console.log(`[${id}]: trying to resolve latest version...`); - const extension = await this.client.getLatestCompatibleExtensionVersion(id); + const client = await this.clientProvider(); + const extension = await client.getLatestCompatibleExtensionVersion(id); if (!extension) { return; } diff --git a/packages/vsx-registry/src/node/vsx-registry-backend-module.ts b/packages/vsx-registry/src/node/vsx-registry-backend-module.ts index cbb4a41f767f5..1905767086110 100644 --- a/packages/vsx-registry/src/node/vsx-registry-backend-module.ts +++ b/packages/vsx-registry/src/node/vsx-registry-backend-module.ts @@ -17,18 +17,20 @@ import { ContainerModule } from '@theia/core/shared/inversify'; import { VSXExtensionResolver } from './vsx-extension-resolver'; import { PluginDeployerResolver } from '@theia/plugin-ext/lib/common/plugin-protocol'; -import { VSCODE_DEFAULT_API_VERSION, VSX_REGISTRY_URL_DEFAULT } from '@theia/plugin-ext-vscode/lib/common/plugin-vscode-types'; -import { OVSXClient } from '@theia/ovsx-client/lib/ovsx-client'; +import { OVSXClientProvider, createOVSXClient } from '../common/ovsx-client-provider'; +import { VSXEnvironment, VSX_ENVIRONMENT_PATH } from '../common/vsx-environment'; +import { VSXEnvironmentImpl } from './vsx-environment-impl'; +import { ConnectionHandler, JsonRpcConnectionHandler } from '@theia/core'; export default new ContainerModule(bind => { - bind(OVSXClient).toConstantValue(new OVSXClient({ - apiVersion: process.env['VSCODE_API_VERSION'] || VSCODE_DEFAULT_API_VERSION, - apiUrl: resolveRegistryUrl() - })); + bind(OVSXClientProvider).toDynamicValue(ctx => { + const clientPromise = createOVSXClient(ctx.container.get(VSXEnvironment)); + return () => clientPromise; + }).inSingletonScope(); + bind(VSXEnvironment).to(VSXEnvironmentImpl).inSingletonScope(); + bind(ConnectionHandler).toDynamicValue( + ctx => new JsonRpcConnectionHandler(VSX_ENVIRONMENT_PATH, () => ctx.container.get(VSXEnvironment)) + ).inSingletonScope(); bind(VSXExtensionResolver).toSelf().inSingletonScope(); bind(PluginDeployerResolver).toService(VSXExtensionResolver); }); - -function resolveRegistryUrl(): string { - return process.env['VSX_REGISTRY_URL'] || VSX_REGISTRY_URL_DEFAULT; -}