boost fetching plugin prefix (#731)
Signed-off-by: Yan Zhang <yanzh@microsoft.com>
This commit is contained in:
Родитель
64d5764440
Коммит
fa46d14f25
|
@ -25,7 +25,7 @@ export class MavenPlugin implements ITreeItem {
|
|||
this.groupId = groupId;
|
||||
this.artifactId = artifactId;
|
||||
this.version = version;
|
||||
taskExecutor.execute(async () => await this.loadMetadata());
|
||||
taskExecutor.execute(async () => await this.fetchPrefix());
|
||||
}
|
||||
|
||||
private get pluginId(): string {
|
||||
|
@ -52,7 +52,7 @@ export class MavenPlugin implements ITreeItem {
|
|||
|
||||
public async getChildren(): Promise<PluginGoal[]> {
|
||||
try {
|
||||
await this.loadMetadata();
|
||||
await this.fetchGoals();
|
||||
} catch (error) {
|
||||
return [];
|
||||
}
|
||||
|
@ -60,20 +60,24 @@ export class MavenPlugin implements ITreeItem {
|
|||
}
|
||||
|
||||
public async refresh(): Promise<void> {
|
||||
this.goals = undefined;
|
||||
await pluginInfoProvider.clearPluginInfo(this.groupId, this.artifactId, this.version);
|
||||
mavenExplorerProvider.refresh(this);
|
||||
}
|
||||
|
||||
private async loadMetadata(): Promise<void> {
|
||||
if (this.prefix !== undefined && this.goals !== undefined) {
|
||||
private async fetchPrefix(): Promise<void> {
|
||||
if (this.prefix !== undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { prefix, goals } = await pluginInfoProvider.getPluginInfo(this.project.pomPath, this.groupId, this.artifactId, this.version);
|
||||
const prefix = await pluginInfoProvider.getPluginPrefix(this.groupId, this.artifactId);
|
||||
this.prefix = prefix;
|
||||
mavenExplorerProvider.refresh(this); // update label/description of current tree item.
|
||||
}
|
||||
|
||||
private async fetchGoals(): Promise<void> {
|
||||
if (this.goals !== undefined) {
|
||||
return;
|
||||
}
|
||||
const goals = await pluginInfoProvider.getPluginGoals(this.project.pomPath, this.groupId, this.artifactId, this.version);
|
||||
this.goals = goals;
|
||||
mavenExplorerProvider.refresh(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,13 +3,22 @@
|
|||
|
||||
import * as _ from "lodash";
|
||||
import * as vscode from "vscode";
|
||||
import { fetchPluginMetadataXml } from "../utils/requestUtils";
|
||||
import { Utils } from "../utils/Utils";
|
||||
|
||||
const KEY_PLUGINS: string = "plugins";
|
||||
|
||||
interface IPluginCache {
|
||||
[groupId: string]: {
|
||||
[artifactId: string]: IPluginInfo
|
||||
};
|
||||
}
|
||||
|
||||
interface IPluginInfo {
|
||||
prefix?: string;
|
||||
goals?: string[];
|
||||
versions?: {
|
||||
[version: string]: string[] // goals
|
||||
};
|
||||
}
|
||||
|
||||
class PluginInfoProvider {
|
||||
|
@ -19,44 +28,63 @@ class PluginInfoProvider {
|
|||
this._context = context;
|
||||
}
|
||||
|
||||
public async getPluginInfo(projectBasePath: string, gid: string, aid: string, version: string): Promise<IPluginInfo> {
|
||||
const cachedResult: IPluginInfo | undefined = await this.getFromLocalCache(gid, aid, version);
|
||||
if (cachedResult) {
|
||||
return cachedResult;
|
||||
public async getPluginPrefix(gid: string, aid: string): Promise<string | undefined> {
|
||||
const infos: {[aid: string]: IPluginInfo} = _.get(this.getPluginCache(), [gid]) ?? {};
|
||||
const info: IPluginInfo = _.get(infos, [aid]) ?? {};
|
||||
if (info.prefix !== undefined) {
|
||||
return info.prefix;
|
||||
}
|
||||
|
||||
const latestResult: IPluginInfo = await this.fetchFromRepository(projectBasePath, gid, aid, version);
|
||||
await this.saveToLocalCache(gid, aid, version, latestResult);
|
||||
return latestResult;
|
||||
const metadataXml = await fetchPluginMetadataXml(gid);
|
||||
const xml: any = await Utils.parseXmlContent(metadataXml);
|
||||
const plugins: any[] = _.get(xml, "metadata.plugins[0].plugin");
|
||||
plugins.forEach(plugin => {
|
||||
const a: string = _.get(plugin, "artifactId[0]");
|
||||
const p: string = _.get(plugin, "prefix[0]");
|
||||
infos[a] = infos[a] ?? {};
|
||||
infos[a].prefix = p;
|
||||
});
|
||||
await this.cachePluginInfos(gid, infos);
|
||||
return infos[aid]?.prefix;
|
||||
}
|
||||
|
||||
public async clearPluginInfo(gid: string, aid: string, version: string): Promise<void> {
|
||||
await this.saveToLocalCache(gid, aid, version, undefined);
|
||||
}
|
||||
|
||||
private async getFromLocalCache(gid: string, aid: string, version: string): Promise<IPluginInfo | undefined> {
|
||||
const plugins: any = this._context.globalState.get(KEY_PLUGINS);
|
||||
return _.get(plugins, [gid, aid, version]);
|
||||
}
|
||||
|
||||
private async saveToLocalCache(gid: string, aid: string, version: string, pluginInfo: IPluginInfo | undefined): Promise<void> {
|
||||
let plugins: any = this._context.globalState.get(KEY_PLUGINS);
|
||||
if (!plugins) {
|
||||
plugins = {};
|
||||
public async getPluginGoals(pomPath: string, groupId: string, artifactId: string, version: string): Promise<string[] | undefined> {
|
||||
const infos: {[aid: string]: IPluginInfo} = _.get(this.getPluginCache(), [groupId]) ?? {};
|
||||
const info: IPluginInfo = _.get(infos, [artifactId]) ?? {};
|
||||
info.versions = info.versions ?? {};
|
||||
const goalsFromCache: string[] | undefined = _.get(info.versions, [version]);
|
||||
if (goalsFromCache !== undefined) {
|
||||
return goalsFromCache;
|
||||
}
|
||||
_.set(plugins, [gid, aid, version], pluginInfo);
|
||||
|
||||
const {prefix, goals} = await this.fetchFromRepository(pomPath, groupId, artifactId, version);
|
||||
info.prefix = info.prefix ?? prefix;
|
||||
info.versions[version] = goals ?? [];
|
||||
|
||||
await this.cachePluginInfo(groupId, artifactId, info);
|
||||
return goals;
|
||||
}
|
||||
|
||||
private getPluginCache(): IPluginCache {
|
||||
return this._context.globalState.get(KEY_PLUGINS) ?? {};
|
||||
}
|
||||
|
||||
private async cachePluginInfos(gid: string, infos: {[aid: string]: IPluginInfo}): Promise<void> {
|
||||
const plugins: any = this._context.globalState.get(KEY_PLUGINS) ?? {};
|
||||
_.set(plugins, [gid], infos);
|
||||
await this._context.globalState.update(KEY_PLUGINS, plugins);
|
||||
}
|
||||
|
||||
private async fetchFromRepository(projectBasePath: string, gid: string, aid: string, version?: string): Promise<IPluginInfo> {
|
||||
private async cachePluginInfo(gid: string, aid: string, info: IPluginInfo): Promise<void> {
|
||||
const plugins: any = this._context.globalState.get(KEY_PLUGINS) ?? {};
|
||||
_.set(plugins, [gid, aid], info);
|
||||
await this._context.globalState.update(KEY_PLUGINS, plugins);
|
||||
}
|
||||
|
||||
private async fetchFromRepository(projectBasePath: string, gid: string, aid: string, version?: string): Promise<{prefix?: string, goals?: string[]}> {
|
||||
let prefix: string | undefined;
|
||||
const goals: string[] = [];
|
||||
const rawOutput: string = await Utils.getPluginDescription(this.getPluginId(gid, aid, version), projectBasePath);
|
||||
|
||||
// Remove ANSI escape code: ESC[m, ESC[1m
|
||||
// To fix: https://github.com/microsoft/vscode-maven/issues/340#issuecomment-511125457
|
||||
const escChar: string = Buffer.from([0x1b]).toString();
|
||||
const textOutput: string = rawOutput.replace(new RegExp(`${escChar}\\[\\d*?m`, "g"), "");
|
||||
const textOutput: string = await Utils.getPluginDescription(this.getPluginId(gid, aid, version), projectBasePath);
|
||||
|
||||
const versionRegExp: RegExp = /^Version: (.*)/m;
|
||||
const versionMatch: string[] | null = textOutput.match(versionRegExp);
|
||||
|
|
|
@ -34,7 +34,7 @@ export async function rawEffectivePom(pomPath: string, options?: {cacheOnly?: bo
|
|||
return await readFileIfExists(epomPath);
|
||||
}
|
||||
|
||||
await executeInBackground(`help:effective-pom -Doutput="${epomPath}"`, pomPath);
|
||||
await executeInBackground(`-B -Doutput="${epomPath}" help:effective-pom`, pomPath);
|
||||
await fse.writeFile(mtimePath, mtimeMs);
|
||||
return await readFileIfExists(epomPath);
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ export async function rawDependencyTree(pomPath: string): Promise<any> {
|
|||
export async function pluginDescription(pluginId: string, pomPath: string): Promise<string | undefined> {
|
||||
const outputPath: string = getTempFolder(pluginId);
|
||||
// For MacOSX, add "-Dapple.awt.UIElement=true" to prevent showing icons in dock
|
||||
await executeInBackground(`help:describe -Dapple.awt.UIElement=true -Dplugin=${pluginId} -Doutput="${outputPath}"`, pomPath);
|
||||
await executeInBackground(`-B -Dapple.awt.UIElement=true -Dplugin=${pluginId} -Doutput="${outputPath}" help:describe`, pomPath);
|
||||
return await readFileIfExists(outputPath);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,9 +4,12 @@
|
|||
import * as http from "http";
|
||||
import * as https from "https";
|
||||
import * as _ from "lodash";
|
||||
import * as path from "path";
|
||||
import * as url from "url";
|
||||
|
||||
const URL_BASIC_SEARCH: string = "https://search.maven.org/solrsearch/select";
|
||||
const URL_MAVEN_SEARCH_API: string = "https://search.maven.org/solrsearch/select";
|
||||
const URL_MAVEN_CENTRAL_REPO: string = "https://repo1.maven.org/maven2/";
|
||||
const MAVEN_METADATA_FILENAME: string = "maven-metadata.xml";
|
||||
|
||||
export interface IArtifactMetadata {
|
||||
id: string;
|
||||
|
@ -37,7 +40,7 @@ export async function getArtifacts(keywords: string[]): Promise<IArtifactMetadat
|
|||
rows: 50,
|
||||
wt: "json"
|
||||
};
|
||||
const raw: string = await httpsGet(`${URL_BASIC_SEARCH}?${toQueryString(params)}`);
|
||||
const raw: string = await httpsGet(`${URL_MAVEN_SEARCH_API}?${toQueryString(params)}`);
|
||||
try {
|
||||
return _.get(JSON.parse(raw), "response.docs", []);
|
||||
} catch (error) {
|
||||
|
@ -53,7 +56,7 @@ export async function getVersions(gid: string, aid: string): Promise<IVersionMet
|
|||
rows: 50,
|
||||
wt: "json"
|
||||
};
|
||||
const raw: string = await httpsGet(`${URL_BASIC_SEARCH}?${toQueryString(params)}`);
|
||||
const raw: string = await httpsGet(`${URL_MAVEN_SEARCH_API}?${toQueryString(params)}`);
|
||||
try {
|
||||
return _.get(JSON.parse(raw), "response.docs", []);
|
||||
} catch (error) {
|
||||
|
@ -69,7 +72,7 @@ export async function getLatestVersion(gid: string, aid: string): Promise<string
|
|||
rows: 1,
|
||||
wt: "json"
|
||||
};
|
||||
const raw: string = await httpsGet(`${URL_BASIC_SEARCH}?${toQueryString(params)}`);
|
||||
const raw: string = await httpsGet(`${URL_MAVEN_SEARCH_API}?${toQueryString(params)}`);
|
||||
return _.get(JSON.parse(raw), "response.docs[0].latestVersion");
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
|
@ -97,3 +100,8 @@ async function httpsGet(urlString: string): Promise<string> {
|
|||
function toQueryString(params: { [key: string]: any }): string {
|
||||
return Object.keys(params).map(k => `${k}=${encodeURIComponent(params[k].toString())}`).join("&");
|
||||
}
|
||||
|
||||
export async function fetchPluginMetadataXml(gid: string): Promise<string> {
|
||||
const metadataUrl = URL_MAVEN_CENTRAL_REPO + path.posix.join(...gid.split("."), MAVEN_METADATA_FILENAME);
|
||||
return await httpsGet(metadataUrl);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче