Signed-off-by: Yan Zhang <yanzh@microsoft.com>
This commit is contained in:
Yan Zhang 2021-09-13 10:37:41 +08:00 коммит произвёл GitHub
Родитель 64d5764440
Коммит fa46d14f25
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
4 изменённых файлов: 84 добавлений и 44 удалений

Просмотреть файл

@ -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);
}