添加在线插件搜索显示的策略,支持网络地址和product.json配置。

1.product.json中添加extensionsControlManifest字段。
    2.extensionsControlManifest字段配置有:
        malicious:此插件不再被维护且已弃用。无可替代的插件。
        search:搜索优先显示列表。
        deprecated:此插件已被弃用。提示可替代的插件。
        migrateToPreRelease:迁移到预发布版。
    3.插件搜索显示列表中弃用的插件不能够安装。
    4.插件搜索关键字时,优先显示kylinIdeTeam开发的插件。
This commit is contained in:
chriswang521 2023-08-31 13:56:56 +08:00
parent 5bfcf91174
commit 5529e077fd
11 changed files with 231 additions and 63 deletions

View File

@ -87,5 +87,118 @@
"linkProtectionTrustedDomains": [ "linkProtectionTrustedDomains": [
"https://open-vsx.org" "https://open-vsx.org"
], ],
"helpDocUrl":"https://gitee.com/openkylin/extensions-repo/blob/master/user-guide/%E7%9B%AE%E5%BD%95.md" "helpDocUrl":"https://gitee.com/openkylin/extensions-repo/blob/master/user-guide/%E7%9B%AE%E5%BD%95.md",
"extensionsControlManifest":{
"malicious": [],
"deprecated": {
"ms-ceintl.vscode-language-pack-zh-hans": {
"disallowInstall": true,
"extension": {
"id": "KylinIdeTeam.vscode-language-pack-zh-hans",
"displayName": "Chinese (Simplified) (简体中文) Language Pack for Kylin-Code"
}
},
"zhanghua.vscodium-language-pack-zh-cn": {
"disallowInstall": true,
"extension": {
"id": "KylinIdeTeam.vscode-language-pack-zh-hans",
"displayName": "Chinese (Simplified) (简体中文) Language Pack for Kylin-Code"
}
}
},
"search": [
{
"query": "c",
"preferredResults": [
"KylinIdeTeam.vscode-clangd",
"KylinIdeTeam.deadlock-detect"
]
},
{
"query": "c++",
"preferredResults": [
"KylinIdeTeam.vscode-clangd",
"KylinIdeTeam.deadlock-detect"
]
},
{
"query": "java",
"preferredResults": [
"KylinIdeTeam.vscode-java-pack",
"KylinIdeTeam.java",
"KylinIdeTeam.vscode-maven",
"KylinIdeTeam.vscode-gradle",
"KylinIdeTeam.vscode-java-dependency",
"KylinIdeTeam.vscode-java-debug",
"KylinIdeTeam.vscode-java-test"
]
},
{
"query": "go",
"preferredResults": [
"KylinIdeTeam.go"
]
},
{
"query": "python",
"preferredResults": [
"KylinIdeTeam.python"
]
},
{
"query": "js",
"preferredResults": [
"KylinIDETeam.js-debug"
]
},
{
"query": "cmake",
"preferredResults": [
"KylinIdeTeam.cmake-intellisence"
]
},
{
"query": "project",
"preferredResults": [
"KylinIdeTeam.project-manager",
"KylinIdeTeam.vscode-java-dependency",
"KylinIdeTeam.vscode-maven"
]
},
{
"query": "debug",
"preferredResults": [
"KylinIdeTeam.debug",
"KylinIDETeam.js-debug",
"KylinIdeTeam.vscode-java-debug",
"KylinIdeTeam.historydebug"
]
},
{
"query": "remote",
"preferredResults": [
"xhafei.remote-dev"
]
},
{
"query": "depend",
"preferredResults": [
"KylinIdeTeam.extension-dependency",
"KylinIdeTeam.vscode-java-dependency"
]
},
{
"query": "extension",
"preferredResults": [
"KylinIdeTeam.extension-dependency"
]
},
{
"query": "extensions",
"preferredResults": [
"KylinIdeTeam.offline-extensions-manager"
]
}
]
}
} }

View File

@ -30,6 +30,31 @@ export type ExtensionVirtualWorkspaceSupport = {
readonly override?: boolean; readonly override?: boolean;
}; };
export interface ISearchPrefferedResults {
readonly query?: string;
readonly preferredResults?: string[];
}
interface IExtensionsControlManifest {
malicious: string[];
migrateToPreRelease?: IStringDictionary<{
id: string;
displayName: string;
migrateStorage?: boolean;
engine?: string;
}>;
deprecated?: IStringDictionary<boolean | {
disallowInstall?: boolean;
extension?: {
id: string;
displayName: string;
};
settings?: string[];
}>;
search?: ISearchPrefferedResults[];
}
export interface IProductConfiguration { export interface IProductConfiguration {
readonly IDEVersion: string; readonly IDEVersion: string;
readonly version: string; readonly version: string;
@ -157,6 +182,8 @@ export interface IProductConfiguration {
readonly 'configurationSync.store'?: ConfigurationSyncStore; readonly 'configurationSync.store'?: ConfigurationSyncStore;
readonly darwinUniversalAssetId?: string; readonly darwinUniversalAssetId?: string;
readonly extensionsControlManifest: IExtensionsControlManifest;
} }
export type ImportantExtensionTip = { name: string; languages?: string[]; pattern?: string; isExtensionPack?: boolean; whenNotInstalled?: string[] }; export type ImportantExtensionTip = { name: string; languages?: string[]; pattern?: string; isExtensionPack?: boolean; whenNotInstalled?: string[] };

View File

@ -579,7 +579,7 @@ export abstract class AbstractExtensionManagementService extends Disposable impl
return manifest; return manifest;
} catch (err) { } catch (err) {
this.logService.trace('ExtensionManagementService.refreshControlCache - failed to get extension control manifest'); this.logService.trace('ExtensionManagementService.refreshControlCache - failed to get extension control manifest');
return { malicious: [], deprecated: {} }; return { malicious: [], deprecated: {}, search: [] };
} }
} }

View File

@ -16,7 +16,7 @@ import { URI } from 'vs/base/common/uri';
import { IRequestContext, IRequestOptions } from 'vs/base/parts/request/common/request'; import { IRequestContext, IRequestOptions } from 'vs/base/parts/request/common/request';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { getFallbackTargetPlarforms, getTargetPlatform, IExtensionGalleryService, IExtensionIdentifier, IExtensionInfo, IGalleryExtension, IGalleryExtensionAsset, IGalleryExtensionAssets, IGalleryExtensionVersion, InstallOperation, IQueryOptions, IExtensionsControlManifest, isNotWebExtensionInWebTargetPlatform, isTargetPlatformCompatible, ITranslation, SortBy, SortOrder, StatisticType, toTargetPlatform, WEB_EXTENSION_TAG, IExtensionQueryOptions, IDeprecationInfo } from 'vs/platform/extensionManagement/common/extensionManagement'; import { getFallbackTargetPlarforms, getTargetPlatform, IExtensionGalleryService, IExtensionIdentifier, IExtensionInfo, IGalleryExtension, IGalleryExtensionAsset, IGalleryExtensionAssets, IGalleryExtensionVersion, InstallOperation, IQueryOptions, IExtensionsControlManifest, isNotWebExtensionInWebTargetPlatform, isTargetPlatformCompatible, ITranslation, SortBy, SortOrder, StatisticType, toTargetPlatform, WEB_EXTENSION_TAG, IExtensionQueryOptions, IDeprecationInfo, ISearchPrefferedResults } from 'vs/platform/extensionManagement/common/extensionManagement';
import { adoptToGalleryExtensionId, areSameExtensions, getGalleryExtensionId, getGalleryExtensionTelemetryData } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { adoptToGalleryExtensionId, areSameExtensions, getGalleryExtensionId, getGalleryExtensionTelemetryData } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { IExtensionManifest, TargetPlatform } from 'vs/platform/extensions/common/extensions'; import { IExtensionManifest, TargetPlatform } from 'vs/platform/extensions/common/extensions';
import { isEngineValid } from 'vs/platform/extensions/common/extensionValidator'; import { isEngineValid } from 'vs/platform/extensions/common/extensionValidator';
@ -562,6 +562,7 @@ interface IRawExtensionsControlManifest {
}; };
settings?: string[]; settings?: string[];
}>; }>;
search?: ISearchPrefferedResults[];
} }
abstract class AbstractExtensionGalleryService implements IExtensionGalleryService { abstract class AbstractExtensionGalleryService implements IExtensionGalleryService {
@ -1181,23 +1182,10 @@ abstract class AbstractExtensionGalleryService implements IExtensionGalleryServi
return engine; return engine;
} }
async getExtensionsControlManifest(): Promise<IExtensionsControlManifest> { async getExtensionsControlManifest1(result: IRawExtensionsControlManifest | null): Promise<IExtensionsControlManifest> {
if (!this.isEnabled()) {
throw new Error('No extension gallery service configured.');
}
if (!this.extensionsControlUrl) {
return { malicious: [], deprecated: {} };
}
const context = await this.requestService.request({ type: 'GET', url: this.extensionsControlUrl }, CancellationToken.None);
if (context.res.statusCode !== 200) {
throw new Error('Could not get extensions report.');
}
const result = await asJson<IRawExtensionsControlManifest>(context);
const malicious: IExtensionIdentifier[] = []; const malicious: IExtensionIdentifier[] = [];
const deprecated: IStringDictionary<IDeprecationInfo> = {}; const deprecated: IStringDictionary<IDeprecationInfo> = {};
const search: ISearchPrefferedResults[] = [];
if (result) { if (result) {
for (const id of result.malicious) { for (const id of result.malicious) {
malicious.push({ id }); malicious.push({ id });
@ -1224,9 +1212,33 @@ abstract class AbstractExtensionGalleryService implements IExtensionGalleryServi
} }
} }
} }
if (result.search) {
for (const s of result.search) {
search.push(s);
}
}
} }
return { malicious, deprecated }; return { malicious, deprecated, search };
}
async getExtensionsControlManifest(): Promise<IExtensionsControlManifest> {
if (!this.isEnabled()) {
throw new Error('No extension gallery service configured.');
}
if (!this.extensionsControlUrl) {
let result: IRawExtensionsControlManifest = this.productService.extensionsControlManifest;
return this.getExtensionsControlManifest1(result);
}
const context = await this.requestService.request({ type: 'GET', url: this.extensionsControlUrl }, CancellationToken.None);
if (context.res.statusCode !== 200) {
throw new Error('Could not get extensions report.');
}
const result = await asJson<IRawExtensionsControlManifest>(context);
return this.getExtensionsControlManifest1(result);
} }
} }

View File

@ -294,9 +294,15 @@ export interface IDeprecationInfo {
readonly settings?: readonly string[]; readonly settings?: readonly string[];
} }
export interface ISearchPrefferedResults {
readonly query?: string;
readonly preferredResults?: string[];
}
export interface IExtensionsControlManifest { export interface IExtensionsControlManifest {
readonly malicious: IExtensionIdentifier[]; readonly malicious: IExtensionIdentifier[];
readonly deprecated: IStringDictionary<IDeprecationInfo>; readonly deprecated: IStringDictionary<IDeprecationInfo>;
readonly search: ISearchPrefferedResults[];
} }
export const enum InstallOperation { export const enum InstallOperation {

View File

@ -33,7 +33,7 @@ import { INotificationService, Severity } from 'vs/platform/notification/common/
import { ViewPane, IViewPaneOptions } from 'vs/workbench/browser/parts/views/viewPane'; import { ViewPane, IViewPaneOptions } from 'vs/workbench/browser/parts/views/viewPane';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { coalesce, distinct, flatten } from 'vs/base/common/arrays'; import { coalesce, distinct, flatten } from 'vs/base/common/arrays';
import { IExperimentService, IExperiment, ExperimentActionType } from 'vs/workbench/contrib/experiments/common/experimentService'; // import { IExperimentService, IExperiment, ExperimentActionType } from 'vs/workbench/contrib/experiments/common/experimentService';
import { alert } from 'vs/base/browser/ui/aria/aria'; import { alert } from 'vs/base/browser/ui/aria/aria';
import { IListContextMenuEvent } from 'vs/base/browser/ui/list/list'; import { IListContextMenuEvent } from 'vs/base/browser/ui/list/list';
import { CancellationToken } from 'vs/base/common/cancellation'; import { CancellationToken } from 'vs/base/common/cancellation';
@ -119,7 +119,7 @@ export class ExtensionsListView extends ViewPane {
@ITelemetryService telemetryService: ITelemetryService, @ITelemetryService telemetryService: ITelemetryService,
@IConfigurationService configurationService: IConfigurationService, @IConfigurationService configurationService: IConfigurationService,
@IWorkspaceContextService protected contextService: IWorkspaceContextService, @IWorkspaceContextService protected contextService: IWorkspaceContextService,
@IExperimentService private readonly experimentService: IExperimentService, // @IExperimentService private readonly experimentService: IExperimentService,
@IExtensionManagementServerService protected readonly extensionManagementServerService: IExtensionManagementServerService, @IExtensionManagementServerService protected readonly extensionManagementServerService: IExtensionManagementServerService,
@IExtensionManifestPropertiesService private readonly extensionManifestPropertiesService: IExtensionManifestPropertiesService, @IExtensionManifestPropertiesService private readonly extensionManifestPropertiesService: IExtensionManifestPropertiesService,
@IWorkbenchExtensionManagementService protected readonly extensionManagementService: IWorkbenchExtensionManagementService, @IWorkbenchExtensionManagementService protected readonly extensionManagementService: IWorkbenchExtensionManagementService,
@ -655,9 +655,9 @@ export class ExtensionsListView extends ViewPane {
return this.queryRecommendations(query, options, token); return this.queryRecommendations(query, options, token);
} }
if (/\bcurated:([^\s]+)\b/.test(query.value)) { // if (/\bcurated:([^\s]+)\b/.test(query.value)) {
return this.getCuratedModel(query, options, token); // return this.getCuratedModel(query, options, token);
} // }
const text = query.value; const text = query.value;
@ -672,15 +672,25 @@ export class ExtensionsListView extends ViewPane {
options.text = text.substring(0, 350); options.text = text.substring(0, 350);
options.source = 'searchText'; options.source = 'searchText';
if (!hasUserDefinedSortOrder) { if (!hasUserDefinedSortOrder) {
const searchExperiments = await this.getSearchExperiments(); // const searchExperiments = await this.getSearchExperiments();
for (const experiment of searchExperiments) { // for (const experiment of searchExperiments) {
if (experiment.action && text.toLowerCase() === experiment.action.properties['searchText'] && Array.isArray(experiment.action.properties['preferredResults'])) { // if (experiment.action && text.toLowerCase() === experiment.action.properties['searchText'] && Array.isArray(experiment.action.properties['preferredResults'])) {
preferredResults = experiment.action.properties['preferredResults']; // preferredResults = experiment.action.properties['preferredResults'];
options.source += `-experiment-${experiment.id}`; // options.source += `-experiment-${experiment.id}`;
// break;
// }
// }
const manifest = await this.extensionManagementService.getExtensionsControlManifest();
const search = manifest.search;
if (Array.isArray(search)) {
for (const s of search) {
if (s.query && s.query.toLowerCase() === text.toLowerCase() && Array.isArray(s.preferredResults)) {
preferredResults = s.preferredResults;
break; break;
} }
} }
} }
}
} else { } else {
options.source = 'viewlet'; options.source = 'viewlet';
} }
@ -704,18 +714,18 @@ export class ExtensionsListView extends ViewPane {
} }
resetSearchExperiments() { ExtensionsListView.searchExperiments = undefined; } // resetSearchExperiments() { ExtensionsListView.searchExperiments = undefined; }
private static searchExperiments: Promise<IExperiment[]> | undefined; // private static searchExperiments: Promise<IExperiment[]> | undefined;
private getSearchExperiments(): Promise<IExperiment[]> { // private getSearchExperiments(): Promise<IExperiment[]> {
if (!ExtensionsListView.searchExperiments) { // if (!ExtensionsListView.searchExperiments) {
ExtensionsListView.searchExperiments = this.experimentService.getExperimentsByType(ExperimentActionType.ExtensionSearchResults) // ExtensionsListView.searchExperiments = this.experimentService.getExperimentsByType(ExperimentActionType.ExtensionSearchResults)
.then(null, e => { // .then(null, e => {
this.logService.error(e); // this.logService.error(e);
return []; // return [];
}); // });
} // }
return ExtensionsListView.searchExperiments; // return ExtensionsListView.searchExperiments;
} // }
private sortExtensions(extensions: IExtension[], options: IQueryOptions): IExtension[] { private sortExtensions(extensions: IExtension[], options: IQueryOptions): IExtension[] {
switch (options.sortBy) { switch (options.sortBy) {
@ -736,19 +746,19 @@ export class ExtensionsListView extends ViewPane {
return extensions; return extensions;
} }
private async getCuratedModel(query: Query, options: IQueryOptions, token: CancellationToken): Promise<IPagedModel<IExtension>> { // private async getCuratedModel(query: Query, options: IQueryOptions, token: CancellationToken): Promise<IPagedModel<IExtension>> {
const value = query.value.replace(/curated:/g, '').trim(); // const value = query.value.replace(/curated:/g, '').trim();
let ids = await this.experimentService.getCuratedExtensionsList(value); // let ids = await this.experimentService.getCuratedExtensionsList(value);
if (Array.isArray(ids) && ids.length) { // if (Array.isArray(ids) && ids.length) {
ids = ids.map(id => id.toLowerCase()); // ids = ids.map(id => id.toLowerCase());
const extensions = await this.extensionsWorkbenchService.getExtensions(ids.map(id => ({ id })), { source: `curated:${value}` }, token); // const extensions = await this.extensionsWorkbenchService.getExtensions(ids.map(id => ({ id })), { source: `curated:${value}` }, token);
// Sorts the firstPage of the pager in the same order as given array of extension ids // // Sorts the firstPage of the pager in the same order as given array of extension ids
extensions.sort((a, b) => // extensions.sort((a, b) =>
ids.indexOf(a.identifier.id.toLowerCase()) < ids.indexOf(b.identifier.id.toLowerCase()) ? -1 : 1); // ids.indexOf(a.identifier.id.toLowerCase()) < ids.indexOf(b.identifier.id.toLowerCase()) ? -1 : 1);
return this.getPagedModel(extensions); // return this.getPagedModel(extensions);
} // }
return new PagedModel([]); // return new PagedModel([]);
} // }
private isRecommendationsQuery(query: Query): boolean { private isRecommendationsQuery(query: Query): boolean {
return ExtensionsListView.isWorkspaceRecommendedExtensionsQuery(query.value) return ExtensionsListView.isWorkspaceRecommendedExtensionsQuery(query.value)

View File

@ -218,7 +218,7 @@ suite('ExtensionRecommendationsService Test', () => {
onDidUninstallExtension: didUninstallEvent.event, onDidUninstallExtension: didUninstallEvent.event,
async getInstalled() { return []; }, async getInstalled() { return []; },
async canInstall() { return true; }, async canInstall() { return true; },
async getExtensionsControlManifest() { return { malicious: [], deprecated: {} }; }, async getExtensionsControlManifest() { return { malicious: [], deprecated: {}, search: [] }; },
async getTargetPlatform() { return getTargetPlatform(platform, arch); } async getTargetPlatform() { return getTargetPlatform(platform, arch); }
}); });
instantiationService.stub(IExtensionService, <Partial<IExtensionService>>{ instantiationService.stub(IExtensionService, <Partial<IExtensionService>>{

View File

@ -100,7 +100,7 @@ async function setupTest() {
onUninstallExtension: uninstallEvent.event, onUninstallExtension: uninstallEvent.event,
onDidUninstallExtension: didUninstallEvent.event, onDidUninstallExtension: didUninstallEvent.event,
async getInstalled() { return []; }, async getInstalled() { return []; },
async getExtensionsControlManifest() { return { malicious: [], deprecated: {} }; }, async getExtensionsControlManifest() { return { malicious: [], deprecated: {}, search: [] }; },
async updateMetadata(local: ILocalExtension, metadata: IGalleryMetadata) { async updateMetadata(local: ILocalExtension, metadata: IGalleryMetadata) {
local.identifier.uuid = metadata.id; local.identifier.uuid = metadata.id;
local.publisherDisplayName = metadata.publisherDisplayName; local.publisherDisplayName = metadata.publisherDisplayName;
@ -2434,7 +2434,7 @@ function createExtensionManagementService(installed: ILocalExtension[] = []): IE
return local; return local;
}, },
async getTargetPlatform() { return getTargetPlatform(platform, arch); }, async getTargetPlatform() { return getTargetPlatform(platform, arch); },
async getExtensionsControlManifest() { return <IExtensionsControlManifest>{ malicious: [], deprecated: {} }; }, async getExtensionsControlManifest() { return <IExtensionsControlManifest>{ malicious: [], deprecated: {}, search: [] }; },
}; };
} }

View File

@ -98,7 +98,7 @@ suite('ExtensionsListView Tests', () => {
onDidUninstallExtension: didUninstallEvent.event, onDidUninstallExtension: didUninstallEvent.event,
async getInstalled() { return []; }, async getInstalled() { return []; },
async canInstall() { return true; }, async canInstall() { return true; },
async getExtensionsControlManifest() { return { malicious: [], deprecated: {} }; }, async getExtensionsControlManifest() { return { malicious: [], deprecated: {}, search: [] }; },
async getTargetPlatform() { return getTargetPlatform(platform, arch); } async getTargetPlatform() { return getTargetPlatform(platform, arch); }
}); });
instantiationService.stub(IRemoteAgentService, RemoteAgentService); instantiationService.stub(IRemoteAgentService, RemoteAgentService);
@ -492,7 +492,7 @@ suite('ExtensionsListView Tests', () => {
} }
}]); }]);
testableView.resetSearchExperiments(); // testableView.resetSearchExperiments();
testableView.dispose(); testableView.dispose();
testableView = instantiationService.createInstance(ExtensionsListView, {}, {}); testableView = instantiationService.createInstance(ExtensionsListView, {}, {});

View File

@ -95,7 +95,7 @@ suite('ExtensionsWorkbenchServiceTest', () => {
onUninstallExtension: uninstallEvent.event, onUninstallExtension: uninstallEvent.event,
onDidUninstallExtension: didUninstallEvent.event, onDidUninstallExtension: didUninstallEvent.event,
async getInstalled() { return []; }, async getInstalled() { return []; },
async getExtensionsControlManifest() { return { malicious: [], deprecated: {} }; }, async getExtensionsControlManifest() { return { malicious: [], deprecated: {}, search: [] }; },
async updateMetadata(local: ILocalExtension, metadata: IGalleryMetadata) { async updateMetadata(local: ILocalExtension, metadata: IGalleryMetadata) {
local.identifier.uuid = metadata.id; local.identifier.uuid = metadata.id;
local.publisherDisplayName = metadata.publisherDisplayName; local.publisherDisplayName = metadata.publisherDisplayName;
@ -1487,7 +1487,7 @@ suite('ExtensionsWorkbenchServiceTest', () => {
return local; return local;
}, },
getTargetPlatform: async () => getTargetPlatform(platform, arch), getTargetPlatform: async () => getTargetPlatform(platform, arch),
async getExtensionsControlManifest() { return <IExtensionsControlManifest>{ malicious: [], deprecated: {} }; }, async getExtensionsControlManifest() { return <IExtensionsControlManifest>{ malicious: [], deprecated: {}, search: [] }; },
}; };
} }
}); });

View File

@ -394,7 +394,7 @@ export class ExtensionManagementService extends Disposable implements IWorkbench
if (this.extensionManagementServerService.webExtensionManagementServer) { if (this.extensionManagementServerService.webExtensionManagementServer) {
return this.extensionManagementServerService.webExtensionManagementServer.extensionManagementService.getExtensionsControlManifest(); return this.extensionManagementServerService.webExtensionManagementServer.extensionManagementService.getExtensionsControlManifest();
} }
return Promise.resolve({ malicious: [], deprecated: {} }); return Promise.resolve({ malicious: [], deprecated: {}, search: [] });
} }
private getServer(extension: ILocalExtension): IExtensionManagementServer | null { private getServer(extension: ILocalExtension): IExtensionManagementServer | null {