添加在线插件搜索显示的策略,支持网络地址和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": [
"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;
};
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 {
readonly IDEVersion: string;
readonly version: string;
@ -157,6 +182,8 @@ export interface IProductConfiguration {
readonly 'configurationSync.store'?: ConfigurationSyncStore;
readonly darwinUniversalAssetId?: string;
readonly extensionsControlManifest: IExtensionsControlManifest;
}
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;
} catch (err) {
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 { IConfigurationService } from 'vs/platform/configuration/common/configuration';
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 { IExtensionManifest, TargetPlatform } from 'vs/platform/extensions/common/extensions';
import { isEngineValid } from 'vs/platform/extensions/common/extensionValidator';
@ -562,6 +562,7 @@ interface IRawExtensionsControlManifest {
};
settings?: string[];
}>;
search?: ISearchPrefferedResults[];
}
abstract class AbstractExtensionGalleryService implements IExtensionGalleryService {
@ -1181,23 +1182,10 @@ abstract class AbstractExtensionGalleryService implements IExtensionGalleryServi
return engine;
}
async getExtensionsControlManifest(): 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);
async getExtensionsControlManifest1(result: IRawExtensionsControlManifest | null): Promise<IExtensionsControlManifest> {
const malicious: IExtensionIdentifier[] = [];
const deprecated: IStringDictionary<IDeprecationInfo> = {};
const search: ISearchPrefferedResults[] = [];
if (result) {
for (const id of result.malicious) {
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[];
}
export interface ISearchPrefferedResults {
readonly query?: string;
readonly preferredResults?: string[];
}
export interface IExtensionsControlManifest {
readonly malicious: IExtensionIdentifier[];
readonly deprecated: IStringDictionary<IDeprecationInfo>;
readonly search: ISearchPrefferedResults[];
}
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 { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
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 { IListContextMenuEvent } from 'vs/base/browser/ui/list/list';
import { CancellationToken } from 'vs/base/common/cancellation';
@ -119,7 +119,7 @@ export class ExtensionsListView extends ViewPane {
@ITelemetryService telemetryService: ITelemetryService,
@IConfigurationService configurationService: IConfigurationService,
@IWorkspaceContextService protected contextService: IWorkspaceContextService,
@IExperimentService private readonly experimentService: IExperimentService,
// @IExperimentService private readonly experimentService: IExperimentService,
@IExtensionManagementServerService protected readonly extensionManagementServerService: IExtensionManagementServerService,
@IExtensionManifestPropertiesService private readonly extensionManifestPropertiesService: IExtensionManifestPropertiesService,
@IWorkbenchExtensionManagementService protected readonly extensionManagementService: IWorkbenchExtensionManagementService,
@ -655,9 +655,9 @@ export class ExtensionsListView extends ViewPane {
return this.queryRecommendations(query, options, token);
}
if (/\bcurated:([^\s]+)\b/.test(query.value)) {
return this.getCuratedModel(query, options, token);
}
// if (/\bcurated:([^\s]+)\b/.test(query.value)) {
// return this.getCuratedModel(query, options, token);
// }
const text = query.value;
@ -672,15 +672,25 @@ export class ExtensionsListView extends ViewPane {
options.text = text.substring(0, 350);
options.source = 'searchText';
if (!hasUserDefinedSortOrder) {
const searchExperiments = await this.getSearchExperiments();
for (const experiment of searchExperiments) {
if (experiment.action && text.toLowerCase() === experiment.action.properties['searchText'] && Array.isArray(experiment.action.properties['preferredResults'])) {
preferredResults = experiment.action.properties['preferredResults'];
options.source += `-experiment-${experiment.id}`;
// const searchExperiments = await this.getSearchExperiments();
// for (const experiment of searchExperiments) {
// if (experiment.action && text.toLowerCase() === experiment.action.properties['searchText'] && Array.isArray(experiment.action.properties['preferredResults'])) {
// preferredResults = experiment.action.properties['preferredResults'];
// 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;
}
}
}
}
} else {
options.source = 'viewlet';
}
@ -704,18 +714,18 @@ export class ExtensionsListView extends ViewPane {
}
resetSearchExperiments() { ExtensionsListView.searchExperiments = undefined; }
private static searchExperiments: Promise<IExperiment[]> | undefined;
private getSearchExperiments(): Promise<IExperiment[]> {
if (!ExtensionsListView.searchExperiments) {
ExtensionsListView.searchExperiments = this.experimentService.getExperimentsByType(ExperimentActionType.ExtensionSearchResults)
.then(null, e => {
this.logService.error(e);
return [];
});
}
return ExtensionsListView.searchExperiments;
}
// resetSearchExperiments() { ExtensionsListView.searchExperiments = undefined; }
// private static searchExperiments: Promise<IExperiment[]> | undefined;
// private getSearchExperiments(): Promise<IExperiment[]> {
// if (!ExtensionsListView.searchExperiments) {
// ExtensionsListView.searchExperiments = this.experimentService.getExperimentsByType(ExperimentActionType.ExtensionSearchResults)
// .then(null, e => {
// this.logService.error(e);
// return [];
// });
// }
// return ExtensionsListView.searchExperiments;
// }
private sortExtensions(extensions: IExtension[], options: IQueryOptions): IExtension[] {
switch (options.sortBy) {
@ -736,19 +746,19 @@ export class ExtensionsListView extends ViewPane {
return extensions;
}
private async getCuratedModel(query: Query, options: IQueryOptions, token: CancellationToken): Promise<IPagedModel<IExtension>> {
const value = query.value.replace(/curated:/g, '').trim();
let ids = await this.experimentService.getCuratedExtensionsList(value);
if (Array.isArray(ids) && ids.length) {
ids = ids.map(id => id.toLowerCase());
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
extensions.sort((a, b) =>
ids.indexOf(a.identifier.id.toLowerCase()) < ids.indexOf(b.identifier.id.toLowerCase()) ? -1 : 1);
return this.getPagedModel(extensions);
}
return new PagedModel([]);
}
// private async getCuratedModel(query: Query, options: IQueryOptions, token: CancellationToken): Promise<IPagedModel<IExtension>> {
// const value = query.value.replace(/curated:/g, '').trim();
// let ids = await this.experimentService.getCuratedExtensionsList(value);
// if (Array.isArray(ids) && ids.length) {
// ids = ids.map(id => id.toLowerCase());
// 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
// extensions.sort((a, b) =>
// ids.indexOf(a.identifier.id.toLowerCase()) < ids.indexOf(b.identifier.id.toLowerCase()) ? -1 : 1);
// return this.getPagedModel(extensions);
// }
// return new PagedModel([]);
// }
private isRecommendationsQuery(query: Query): boolean {
return ExtensionsListView.isWorkspaceRecommendedExtensionsQuery(query.value)

View File

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

View File

@ -100,7 +100,7 @@ async function setupTest() {
onUninstallExtension: uninstallEvent.event,
onDidUninstallExtension: didUninstallEvent.event,
async getInstalled() { return []; },
async getExtensionsControlManifest() { return { malicious: [], deprecated: {} }; },
async getExtensionsControlManifest() { return { malicious: [], deprecated: {}, search: [] }; },
async updateMetadata(local: ILocalExtension, metadata: IGalleryMetadata) {
local.identifier.uuid = metadata.id;
local.publisherDisplayName = metadata.publisherDisplayName;
@ -2434,7 +2434,7 @@ function createExtensionManagementService(installed: ILocalExtension[] = []): IE
return local;
},
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,
async getInstalled() { return []; },
async canInstall() { return true; },
async getExtensionsControlManifest() { return { malicious: [], deprecated: {} }; },
async getExtensionsControlManifest() { return { malicious: [], deprecated: {}, search: [] }; },
async getTargetPlatform() { return getTargetPlatform(platform, arch); }
});
instantiationService.stub(IRemoteAgentService, RemoteAgentService);
@ -492,7 +492,7 @@ suite('ExtensionsListView Tests', () => {
}
}]);
testableView.resetSearchExperiments();
// testableView.resetSearchExperiments();
testableView.dispose();
testableView = instantiationService.createInstance(ExtensionsListView, {}, {});

View File

@ -95,7 +95,7 @@ suite('ExtensionsWorkbenchServiceTest', () => {
onUninstallExtension: uninstallEvent.event,
onDidUninstallExtension: didUninstallEvent.event,
async getInstalled() { return []; },
async getExtensionsControlManifest() { return { malicious: [], deprecated: {} }; },
async getExtensionsControlManifest() { return { malicious: [], deprecated: {}, search: [] }; },
async updateMetadata(local: ILocalExtension, metadata: IGalleryMetadata) {
local.identifier.uuid = metadata.id;
local.publisherDisplayName = metadata.publisherDisplayName;
@ -1487,7 +1487,7 @@ suite('ExtensionsWorkbenchServiceTest', () => {
return local;
},
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) {
return this.extensionManagementServerService.webExtensionManagementServer.extensionManagementService.getExtensionsControlManifest();
}
return Promise.resolve({ malicious: [], deprecated: {} });
return Promise.resolve({ malicious: [], deprecated: {}, search: [] });
}
private getServer(extension: ILocalExtension): IExtensionManagementServer | null {