mirror of https://github.com/microsoft/vscode.git
adopt extension resource url to gallery manifest (#244105)
This commit is contained in:
parent
5fa41d4575
commit
ea8c62369e
|
@ -14,6 +14,7 @@ export const enum ExtensionGalleryResourceType {
|
|||
PublisherViewUri = 'PublisherViewUriTemplate',
|
||||
ExtensionDetailsViewUri = 'ExtensionDetailsViewUriTemplate',
|
||||
ExtensionRatingViewUri = 'ExtensionRatingViewUriTemplate',
|
||||
ExtensionResourceUri = 'ExtensionResourceUriTemplate',
|
||||
}
|
||||
|
||||
export const enum Flag {
|
||||
|
@ -68,4 +69,18 @@ export interface IExtensionGalleryManifestService {
|
|||
getExtensionGalleryManifest(): Promise<IExtensionGalleryManifest | null>;
|
||||
}
|
||||
|
||||
export function getExtensionGalleryManifestResourceUri(manifest: IExtensionGalleryManifest, type: ExtensionGalleryResourceType, version?: string): string | undefined {
|
||||
for (const resource of manifest.resources) {
|
||||
const [r, v] = resource.type.split('/');
|
||||
if (r !== type) {
|
||||
continue;
|
||||
}
|
||||
if (!version || v === version) {
|
||||
return resource.id;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export const ExtensionGalleryServiceUrlConfigKey = 'extensions.gallery.serviceUrl';
|
||||
|
|
|
@ -77,6 +77,13 @@ export class ExtensionGalleryManifestService extends Disposable implements IExte
|
|||
});
|
||||
}
|
||||
|
||||
if (extensionsGallery.resourceUrlTemplate) {
|
||||
resources.push({
|
||||
id: extensionsGallery.resourceUrlTemplate,
|
||||
type: ExtensionGalleryResourceType.ExtensionResourceUri
|
||||
});
|
||||
}
|
||||
|
||||
const filtering = [
|
||||
{
|
||||
name: FilterType.Tag,
|
||||
|
|
|
@ -29,7 +29,7 @@ import { ITelemetryService } from '../../telemetry/common/telemetry.js';
|
|||
import { StopWatch } from '../../../base/common/stopwatch.js';
|
||||
import { format2 } from '../../../base/common/strings.js';
|
||||
import { IAssignmentService } from '../../assignment/common/assignment.js';
|
||||
import { ExtensionGalleryResourceType, Flag, IExtensionGalleryManifest, IExtensionGalleryManifestService } from './extensionGalleryManifest.js';
|
||||
import { ExtensionGalleryResourceType, Flag, getExtensionGalleryManifestResourceUri, IExtensionGalleryManifest, IExtensionGalleryManifestService } from './extensionGalleryManifest.js';
|
||||
|
||||
const CURRENT_TARGET_PLATFORM = isWeb ? TargetPlatform.WEB : getTargetPlatform(platform, arch);
|
||||
const SEARCH_ACTIVITY_HEADER_NAME = 'X-Market-Search-Activity-Id';
|
||||
|
@ -441,20 +441,6 @@ function setTelemetry(extension: IGalleryExtension, index: number, querySource?:
|
|||
extension.telemetryData = { index, querySource, queryActivityId: extension.queryContext?.[SEARCH_ACTIVITY_HEADER_NAME] };
|
||||
}
|
||||
|
||||
function getExtensionGalleryManifestResourceUri(manifest: IExtensionGalleryManifest, type: ExtensionGalleryResourceType, version?: string): string | undefined {
|
||||
for (const resource of manifest.resources) {
|
||||
const [r, v] = resource.type.split('/');
|
||||
if (r !== type) {
|
||||
continue;
|
||||
}
|
||||
if (!version || v === version) {
|
||||
return resource.id;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function toExtension(galleryExtension: IRawGalleryExtension, version: IRawGalleryExtensionVersion, allTargetPlatforms: TargetPlatform[], extensionGalleryManifest: IExtensionGalleryManifest, queryContext?: IStringDictionary<any>): IGalleryExtension {
|
||||
const latestVersion = galleryExtension.versions[0];
|
||||
const assets: IGalleryExtensionAssets = {
|
||||
|
|
|
@ -13,6 +13,7 @@ import { IEnvironmentService } from '../../environment/common/environment.js';
|
|||
import { ILogService } from '../../log/common/log.js';
|
||||
import { IConfigurationService } from '../../configuration/common/configuration.js';
|
||||
import { AbstractExtensionResourceLoaderService, IExtensionResourceLoaderService } from '../common/extensionResourceLoader.js';
|
||||
import { IExtensionGalleryManifestService } from '../../extensionManagement/common/extensionGalleryManifest.js';
|
||||
|
||||
class ExtensionResourceLoaderService extends AbstractExtensionResourceLoaderService {
|
||||
|
||||
|
@ -24,9 +25,10 @@ class ExtensionResourceLoaderService extends AbstractExtensionResourceLoaderServ
|
|||
@IProductService productService: IProductService,
|
||||
@IEnvironmentService environmentService: IEnvironmentService,
|
||||
@IConfigurationService configurationService: IConfigurationService,
|
||||
@ILogService private readonly _logService: ILogService,
|
||||
@IExtensionGalleryManifestService extensionGalleryManifestService: IExtensionGalleryManifestService,
|
||||
@ILogService logService: ILogService,
|
||||
) {
|
||||
super(fileService, storageService, productService, environmentService, configurationService);
|
||||
super(fileService, storageService, productService, environmentService, configurationService, extensionGalleryManifestService, logService);
|
||||
}
|
||||
|
||||
async readExtensionResource(uri: URI): Promise<string> {
|
||||
|
@ -38,7 +40,7 @@ class ExtensionResourceLoaderService extends AbstractExtensionResourceLoaderServ
|
|||
}
|
||||
|
||||
const requestInit: RequestInit = {};
|
||||
if (this.isExtensionGalleryResource(uri)) {
|
||||
if (await this.isExtensionGalleryResource(uri)) {
|
||||
requestInit.headers = await this.getExtensionGalleryRequestHeaders();
|
||||
requestInit.mode = 'cors'; /* set mode to cors so that above headers are always passed */
|
||||
}
|
||||
|
|
|
@ -17,6 +17,9 @@ import { TelemetryLevel } from '../../telemetry/common/telemetry.js';
|
|||
import { getTelemetryLevel, supportsTelemetry } from '../../telemetry/common/telemetryUtils.js';
|
||||
import { RemoteAuthorities } from '../../../base/common/network.js';
|
||||
import { TargetPlatform } from '../../extensions/common/extensions.js';
|
||||
import { ExtensionGalleryResourceType, getExtensionGalleryManifestResourceUri, IExtensionGalleryManifest, IExtensionGalleryManifestService } from '../../extensionManagement/common/extensionGalleryManifest.js';
|
||||
import { ILogService } from '../../log/common/log.js';
|
||||
import { Disposable } from '../../../base/common/lifecycle.js';
|
||||
|
||||
const WEB_EXTENSION_RESOURCE_END_POINT_SEGMENT = '/web-extension-resource/';
|
||||
|
||||
|
@ -36,17 +39,17 @@ export interface IExtensionResourceLoaderService {
|
|||
/**
|
||||
* Returns whether the gallery provides extension resources.
|
||||
*/
|
||||
readonly supportsExtensionGalleryResources: boolean;
|
||||
supportsExtensionGalleryResources(): Promise<boolean>;
|
||||
|
||||
/**
|
||||
* Return true if the given URI is a extension gallery resource.
|
||||
*/
|
||||
isExtensionGalleryResource(uri: URI): boolean;
|
||||
isExtensionGalleryResource(uri: URI): Promise<boolean>;
|
||||
|
||||
/**
|
||||
* Computes the URL of a extension gallery resource. Returns `undefined` if gallery does not provide extension resources.
|
||||
*/
|
||||
getExtensionGalleryResourceURL(galleryExtension: { publisher: string; name: string; version: string; targetPlatform?: TargetPlatform }, path?: string): URI | undefined;
|
||||
getExtensionGalleryResourceURL(galleryExtension: { publisher: string; name: string; version: string; targetPlatform?: TargetPlatform }, path?: string): Promise<URI | undefined>;
|
||||
}
|
||||
|
||||
export function migratePlatformSpecificExtensionGalleryResourceURL(resource: URI, targetPlatform: TargetPlatform): URI | undefined {
|
||||
|
@ -61,12 +64,14 @@ export function migratePlatformSpecificExtensionGalleryResourceURL(resource: URI
|
|||
return resource.with({ query: null, path: paths.join('/') });
|
||||
}
|
||||
|
||||
export abstract class AbstractExtensionResourceLoaderService implements IExtensionResourceLoaderService {
|
||||
export abstract class AbstractExtensionResourceLoaderService extends Disposable implements IExtensionResourceLoaderService {
|
||||
|
||||
readonly _serviceBrand: undefined;
|
||||
|
||||
private readonly _extensionGalleryResourceUrlTemplate: string | undefined;
|
||||
private readonly _extensionGalleryAuthority: string | undefined;
|
||||
private readonly _initPromise: Promise<void>;
|
||||
|
||||
private _extensionGalleryResourceUrlTemplate: string | undefined;
|
||||
private _extensionGalleryAuthority: string | undefined;
|
||||
|
||||
constructor(
|
||||
protected readonly _fileService: IFileService,
|
||||
|
@ -74,18 +79,35 @@ export abstract class AbstractExtensionResourceLoaderService implements IExtensi
|
|||
private readonly _productService: IProductService,
|
||||
private readonly _environmentService: IEnvironmentService,
|
||||
private readonly _configurationService: IConfigurationService,
|
||||
private readonly _extensionGalleryManifestService: IExtensionGalleryManifestService,
|
||||
protected readonly _logService: ILogService,
|
||||
) {
|
||||
if (_productService.extensionsGallery) {
|
||||
this._extensionGalleryResourceUrlTemplate = _productService.extensionsGallery.resourceUrlTemplate;
|
||||
this._extensionGalleryAuthority = this._extensionGalleryResourceUrlTemplate ? this._getExtensionGalleryAuthority(URI.parse(this._extensionGalleryResourceUrlTemplate)) : undefined;
|
||||
super();
|
||||
this._initPromise = this._init();
|
||||
}
|
||||
|
||||
private async _init(): Promise<void> {
|
||||
try {
|
||||
const manifest = await this._extensionGalleryManifestService.getExtensionGalleryManifest();
|
||||
this.resolve(manifest);
|
||||
this._register(this._extensionGalleryManifestService.onDidChangeExtensionGalleryManifest(() => this.resolve(manifest)));
|
||||
} catch (error) {
|
||||
this._logService.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
public get supportsExtensionGalleryResources(): boolean {
|
||||
private resolve(manifest: IExtensionGalleryManifest | null): void {
|
||||
this._extensionGalleryResourceUrlTemplate = manifest ? getExtensionGalleryManifestResourceUri(manifest, ExtensionGalleryResourceType.ExtensionResourceUri) : undefined;
|
||||
this._extensionGalleryAuthority = this._extensionGalleryResourceUrlTemplate ? this._getExtensionGalleryAuthority(URI.parse(this._extensionGalleryResourceUrlTemplate)) : undefined;
|
||||
}
|
||||
|
||||
public async supportsExtensionGalleryResources(): Promise<boolean> {
|
||||
await this._initPromise;
|
||||
return this._extensionGalleryResourceUrlTemplate !== undefined;
|
||||
}
|
||||
|
||||
public getExtensionGalleryResourceURL({ publisher, name, version, targetPlatform }: { publisher: string; name: string; version: string; targetPlatform?: TargetPlatform }, path?: string): URI | undefined {
|
||||
public async getExtensionGalleryResourceURL({ publisher, name, version, targetPlatform }: { publisher: string; name: string; version: string; targetPlatform?: TargetPlatform }, path?: string): Promise<URI | undefined> {
|
||||
await this._initPromise;
|
||||
if (this._extensionGalleryResourceUrlTemplate) {
|
||||
const uri = URI.parse(format2(this._extensionGalleryResourceUrlTemplate, {
|
||||
publisher,
|
||||
|
@ -105,7 +127,8 @@ export abstract class AbstractExtensionResourceLoaderService implements IExtensi
|
|||
|
||||
public abstract readExtensionResource(uri: URI): Promise<string>;
|
||||
|
||||
isExtensionGalleryResource(uri: URI): boolean {
|
||||
async isExtensionGalleryResource(uri: URI): Promise<boolean> {
|
||||
await this._initPromise;
|
||||
return !!this._extensionGalleryAuthority && this._extensionGalleryAuthority === this._getExtensionGalleryAuthority(uri);
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,8 @@ import { IEnvironmentService } from '../../environment/common/environment.js';
|
|||
import { IConfigurationService } from '../../configuration/common/configuration.js';
|
||||
import { CancellationToken } from '../../../base/common/cancellation.js';
|
||||
import { AbstractExtensionResourceLoaderService, IExtensionResourceLoaderService } from './extensionResourceLoader.js';
|
||||
import { IExtensionGalleryManifestService } from '../../extensionManagement/common/extensionGalleryManifest.js';
|
||||
import { ILogService } from '../../log/common/log.js';
|
||||
|
||||
export class ExtensionResourceLoaderService extends AbstractExtensionResourceLoaderService {
|
||||
|
||||
|
@ -22,13 +24,15 @@ export class ExtensionResourceLoaderService extends AbstractExtensionResourceLoa
|
|||
@IProductService productService: IProductService,
|
||||
@IEnvironmentService environmentService: IEnvironmentService,
|
||||
@IConfigurationService configurationService: IConfigurationService,
|
||||
@IExtensionGalleryManifestService extensionGalleryManifestService: IExtensionGalleryManifestService,
|
||||
@IRequestService private readonly _requestService: IRequestService,
|
||||
@ILogService logService: ILogService,
|
||||
) {
|
||||
super(fileService, storageService, productService, environmentService, configurationService);
|
||||
super(fileService, storageService, productService, environmentService, configurationService, extensionGalleryManifestService, logService);
|
||||
}
|
||||
|
||||
async readExtensionResource(uri: URI): Promise<string> {
|
||||
if (this.isExtensionGalleryResource(uri)) {
|
||||
if (await this.isExtensionGalleryResource(uri)) {
|
||||
const headers = await this.getExtensionGalleryRequestHeaders();
|
||||
const requestContext = await this._requestService.request({ url: uri.toString(), headers }, CancellationToken.None);
|
||||
return (await asTextOrError(requestContext)) || '';
|
||||
|
|
|
@ -56,7 +56,7 @@ export class WebLanguagePacksService extends LanguagePackBaseService {
|
|||
}
|
||||
|
||||
// get the resource uri and return it
|
||||
const uri = this.extensionResourceLoaderService.getExtensionGalleryResourceURL({
|
||||
const uri = await this.extensionResourceLoaderService.getExtensionGalleryResourceURL({
|
||||
// If translation is defined then manifest should have been defined.
|
||||
name: manifest!.name,
|
||||
publisher: manifest!.publisher,
|
||||
|
|
|
@ -306,7 +306,7 @@ class InstalledThemesPicker {
|
|||
|
||||
let marketplaceThemePicker: MarketplaceThemesPicker | undefined;
|
||||
if (this.extensionGalleryService.isEnabled()) {
|
||||
if (this.extensionResourceLoaderService.supportsExtensionGalleryResources && this.options.browseMessage) {
|
||||
if (await this.extensionResourceLoaderService.supportsExtensionGalleryResources() && this.options.browseMessage) {
|
||||
marketplaceThemePicker = this.instantiationService.createInstance(MarketplaceThemesPicker, this.getMarketplaceColorThemes.bind(this), this.options.marketplaceTag);
|
||||
picks = [configurationEntry(this.options.browseMessage, ConfigureItem.BROWSE_GALLERY), ...picks];
|
||||
} else {
|
||||
|
@ -772,7 +772,7 @@ registerAction2(class extends Action2 {
|
|||
const extensionResourceLoaderService = accessor.get(IExtensionResourceLoaderService);
|
||||
const instantiationService = accessor.get(IInstantiationService);
|
||||
|
||||
if (!extensionGalleryService.isEnabled() || !extensionResourceLoaderService.supportsExtensionGalleryResources) {
|
||||
if (!extensionGalleryService.isEnabled() || !await extensionResourceLoaderService.supportsExtensionGalleryResources()) {
|
||||
return;
|
||||
}
|
||||
const currentTheme = themeService.getColorTheme();
|
||||
|
|
|
@ -146,7 +146,7 @@ export class WebExtensionsScannerService extends Disposable implements IWebExten
|
|||
}
|
||||
} else if (isUriComponents(e)) {
|
||||
const extensionLocation = URI.revive(e);
|
||||
if (this.extensionResourceLoaderService.isExtensionGalleryResource(extensionLocation)) {
|
||||
if (await this.extensionResourceLoaderService.isExtensionGalleryResource(extensionLocation)) {
|
||||
extensionGalleryResources.push(extensionLocation);
|
||||
} else {
|
||||
extensionLocations.push(extensionLocation);
|
||||
|
@ -651,7 +651,7 @@ export class WebExtensionsScannerService extends Disposable implements IWebExten
|
|||
}
|
||||
|
||||
private async toWebExtensionFromGallery(galleryExtension: IGalleryExtension, metadata?: Metadata): Promise<IWebExtension> {
|
||||
const extensionLocation = this.extensionResourceLoaderService.getExtensionGalleryResourceURL({
|
||||
const extensionLocation = await this.extensionResourceLoaderService.getExtensionGalleryResourceURL({
|
||||
publisher: galleryExtension.publisher,
|
||||
name: galleryExtension.name,
|
||||
version: galleryExtension.version,
|
||||
|
|
|
@ -375,7 +375,7 @@ export class WorkbenchThemeService extends Disposable implements IWorkbenchTheme
|
|||
}
|
||||
|
||||
public async getMarketplaceColorThemes(publisher: string, name: string, version: string): Promise<IWorkbenchColorTheme[]> {
|
||||
const extensionLocation = this.extensionResourceLoaderService.getExtensionGalleryResourceURL({ publisher, name, version }, 'extension');
|
||||
const extensionLocation = await this.extensionResourceLoaderService.getExtensionGalleryResourceURL({ publisher, name, version }, 'extension');
|
||||
if (extensionLocation) {
|
||||
try {
|
||||
const manifestContent = await this.extensionResourceLoaderService.readExtensionResource(resources.joinPath(extensionLocation, 'package.json'));
|
||||
|
@ -599,7 +599,7 @@ export class WorkbenchThemeService extends Disposable implements IWorkbenchTheme
|
|||
}
|
||||
|
||||
public async getMarketplaceFileIconThemes(publisher: string, name: string, version: string): Promise<IWorkbenchFileIconTheme[]> {
|
||||
const extensionLocation = this.extensionResourceLoaderService.getExtensionGalleryResourceURL({ publisher, name, version }, 'extension');
|
||||
const extensionLocation = await this.extensionResourceLoaderService.getExtensionGalleryResourceURL({ publisher, name, version }, 'extension');
|
||||
if (extensionLocation) {
|
||||
try {
|
||||
const manifestContent = await this.extensionResourceLoaderService.readExtensionResource(resources.joinPath(extensionLocation, 'package.json'));
|
||||
|
@ -705,7 +705,7 @@ export class WorkbenchThemeService extends Disposable implements IWorkbenchTheme
|
|||
}
|
||||
|
||||
public async getMarketplaceProductIconThemes(publisher: string, name: string, version: string): Promise<IWorkbenchProductIconTheme[]> {
|
||||
const extensionLocation = this.extensionResourceLoaderService.getExtensionGalleryResourceURL({ publisher, name, version }, 'extension');
|
||||
const extensionLocation = await this.extensionResourceLoaderService.getExtensionGalleryResourceURL({ publisher, name, version }, 'extension');
|
||||
if (extensionLocation) {
|
||||
try {
|
||||
const manifestContent = await this.extensionResourceLoaderService.readExtensionResource(resources.joinPath(extensionLocation, 'package.json'));
|
||||
|
|
|
@ -21,6 +21,7 @@ import { IStorageService } from '../../../../../platform/storage/common/storage.
|
|||
import { IEnvironmentService } from '../../../../../platform/environment/common/environment.js';
|
||||
import { IConfigurationService } from '../../../../../platform/configuration/common/configuration.js';
|
||||
import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js';
|
||||
import { ExtensionGalleryManifestService } from '../../../../../platform/extensionManagement/common/extensionGalleryManifestService.js';
|
||||
|
||||
const undefinedStyle = { bold: undefined, underline: undefined, italic: undefined };
|
||||
const unsetStyle = { bold: false, underline: false, italic: false };
|
||||
|
@ -89,7 +90,7 @@ suite('Themes - TokenStyleResolving', () => {
|
|||
const environmentService = new (mock<IEnvironmentService>())();
|
||||
const configurationService = new (mock<IConfigurationService>())();
|
||||
|
||||
const extensionResourceLoaderService = new ExtensionResourceLoaderService(fileService, storageService, TestProductService, environmentService, configurationService, requestService);
|
||||
const extensionResourceLoaderService = new ExtensionResourceLoaderService(fileService, storageService, TestProductService, environmentService, configurationService, new ExtensionGalleryManifestService(TestProductService), requestService, new NullLogService());
|
||||
|
||||
const diskFileSystemProvider = new DiskFileSystemProvider(new NullLogService());
|
||||
fileService.registerProvider(Schemas.file, diskFileSystemProvider);
|
||||
|
|
Loading…
Reference in New Issue