Allow to view/execute plugin specified goals. (#157)

* Refactor and add Plugins node.

* Make explorer provider static.

* Can list plugin goals.

* Fetch plugins from effective-pom

* Add command to execute plugin goals

* Add icons for plugins

* Renaming.
This commit is contained in:
Yan Zhang 2018-12-04 18:24:30 +08:00
Родитель f97f7f8538
Коммит 3120dc1a9a
22 изменённых файлов: 531 добавлений и 207 удалений

10
package-lock.json сгенерированный
Просмотреть файл

@ -13,6 +13,11 @@
"@types/node": "*"
}
},
"@types/lodash": {
"version": "4.14.118",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.118.tgz",
"integrity": "sha512-iiJbKLZbhSa6FYRip/9ZDX6HXhayXLDGY2Fqws9cOkEQ6XeKfaxB0sC541mowZJueYyMnVUmmG+al5/4fCDrgw=="
},
"@types/md5": {
"version": "2.1.32",
"resolved": "https://registry.npmjs.org/@types/md5/-/md5-2.1.32.tgz",
@ -1547,6 +1552,11 @@
"flush-write-stream": "^1.0.2"
}
},
"lodash": {
"version": "4.17.11",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
"integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg=="
},
"lodash.isequal": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",

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

@ -41,7 +41,8 @@
"onCommand:maven.project.openPom",
"onCommand:maven.archetype.generate",
"onCommand:maven.archetype.update",
"onCommand:maven.history"
"onCommand:maven.history",
"onCommand:maven.plugin.execute"
],
"main": "./out/extension",
"contributes": {
@ -134,6 +135,11 @@
"command": "maven.goal.execute",
"title": "%contributes.commands.maven.goal.execute%",
"category": "Maven"
},
{
"command": "maven.plugin.execute",
"title": "%contributes.commands.maven.plugin.execute%",
"category": "Maven"
}
],
"views": {
@ -221,63 +227,68 @@
"view/item/context": [
{
"command": "maven.goal.custom",
"when": "view == mavenProjects && viewItem == ProjectItem",
"when": "view == mavenProjects && viewItem == MavenProject",
"group": "1-lifecycle@5"
},
{
"command": "maven.history",
"when": "view == mavenProjects && viewItem == ProjectItem",
"when": "view == mavenProjects && viewItem == MavenProject",
"group": "1-lifecycle@0"
},
{
"command": "maven.goal.clean",
"when": "view == mavenProjects && viewItem == ProjectItem",
"when": "view == mavenProjects && viewItem == MavenProject",
"group": "1-lifecycle@10"
},
{
"command": "maven.goal.package",
"when": "view == mavenProjects && viewItem == ProjectItem",
"when": "view == mavenProjects && viewItem == MavenProject",
"group": "1-lifecycle@20"
},
{
"command": "maven.goal.install",
"when": "view == mavenProjects && viewItem == ProjectItem",
"when": "view == mavenProjects && viewItem == MavenProject",
"group": "1-lifecycle@30"
},
{
"command": "maven.goal.compile",
"when": "view == mavenProjects && viewItem == ProjectItem",
"when": "view == mavenProjects && viewItem == MavenProject",
"group": "1-lifecycle@40"
},
{
"command": "maven.goal.validate",
"when": "view == mavenProjects && viewItem == ProjectItem",
"when": "view == mavenProjects && viewItem == MavenProject",
"group": "1-lifecycle@50"
},
{
"command": "maven.goal.verify",
"when": "view == mavenProjects && viewItem == ProjectItem",
"when": "view == mavenProjects && viewItem == MavenProject",
"group": "1-lifecycle@60"
},
{
"command": "maven.goal.test",
"when": "view == mavenProjects && viewItem == ProjectItem",
"when": "view == mavenProjects && viewItem == MavenProject",
"group": "1-lifecycle@70"
},
{
"command": "maven.goal.site",
"when": "view == mavenProjects && viewItem == ProjectItem",
"when": "view == mavenProjects && viewItem == MavenProject",
"group": "1-lifecycle@80"
},
{
"command": "maven.goal.deploy",
"when": "view == mavenProjects && viewItem == ProjectItem",
"when": "view == mavenProjects && viewItem == MavenProject",
"group": "1-lifecycle@90"
},
{
"command": "maven.project.effectivePom",
"when": "view == mavenProjects && viewItem == ProjectItem",
"when": "view == mavenProjects && viewItem == MavenProject",
"group": "0-pom@1"
},
{
"command": "maven.plugin.execute",
"when": "view == mavenProjects && viewItem == PluginGoal",
"group": "1@1"
}
]
},
@ -365,7 +376,9 @@
"vscode": "^1.1.22"
},
"dependencies": {
"@types/lodash": "^4.14.118",
"fs-extra": "^4.0.3",
"lodash": "^4.17.11",
"md5": "^2.2.1",
"minimatch": "^3.0.4",
"vscode-extension-telemetry-wrapper": "0.3.6",

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

@ -8,6 +8,7 @@
"contributes.commands.maven.archetype.update": "Update Maven Archetype Catalog",
"contributes.commands.maven.history": "History ...",
"contributes.commands.maven.goal.execute": "Execute commands",
"contributes.commands.maven.plugin.execute": "Execute",
"contributes.views.explorer.mavenProjects": "Maven Projects",
"configuration.maven.excludedFolders": "Specifies filepath pattern of folders to exclude while searching for Maven projects.",

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

@ -8,6 +8,7 @@
"contributes.commands.maven.archetype.update": "更新Maven原型目录",
"contributes.commands.maven.history": "历史 ...",
"contributes.commands.maven.goal.execute": "执行命令",
"contributes.commands.maven.plugin.execute": "执行",
"contributes.views.explorer.mavenProjects": "Maven项目",
"configuration.maven.excludedFolders": "指定搜索Maven项目时要排除的文件夹。",

42
resources/dark/plugin.svg Normal file
Просмотреть файл

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Capa_1" x="0px" y="0px" width="512px" height="512px" viewBox="0 0 99.012 99.012" style="enable-background:new 0 0 99.012 99.012;" xml:space="preserve">
<g>
<g>
<path d="M25.08,15.648c-0.478-0.478-1.135-0.742-1.805-0.723c-0.675,0.017-1.314,0.309-1.768,0.808 c-14.829,16.325-6.762,51.623-5.916,55.115L0.723,85.717C0.26,86.18,0,86.808,0,87.463c0,0.654,0.26,1.283,0.723,1.746 l8.958,8.957c0.482,0.48,1.114,0.723,1.746,0.723c0.631,0,1.264-0.24,1.745-0.723l14.865-14.864 c7.237,1.859,16.289,2.968,24.28,2.968c9.599,0,22.739-1.543,30.836-8.886c0.5-0.454,0.793-1.093,0.809-1.769 c0.018-0.676-0.245-1.328-0.723-1.805L25.08,15.648z" fill="#c5c5c5"/>
<path d="M46.557,30.345c0.482,0.482,1.114,0.723,1.746,0.723c0.632,0,1.264-0.241,1.746-0.724l18.428-18.428 c1.305-1.305,2.023-3.04,2.023-4.885c0-1.846-0.719-3.582-2.023-4.886c-1.305-1.305-3.039-2.022-4.885-2.022 c-1.845,0-3.581,0.718-4.887,2.022L40.277,20.574c-0.964,0.964-0.964,2.527,0,3.492L46.557,30.345z" fill="#c5c5c5"/>
<path d="M96.99,30.661c-1.305-1.305-3.039-2.024-4.885-2.024c-1.847,0-3.582,0.718-4.886,2.023L68.79,49.089 c-0.464,0.463-0.724,1.091-0.724,1.746s0.26,1.282,0.724,1.746l6.28,6.278c0.481,0.482,1.113,0.724,1.746,0.724 c0.631,0,1.264-0.241,1.746-0.724l18.43-18.429C99.686,37.735,99.686,33.353,96.99,30.661z" fill="#c5c5c5"/>
</g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

После

Ширина:  |  Высота:  |  Размер: 1.8 KiB

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

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Capa_1" x="0px" y="0px" width="512px" height="512px" viewBox="0 0 99.012 99.012" style="enable-background:new 0 0 99.012 99.012;" xml:space="preserve">
<g>
<g>
<path d="M25.08,15.648c-0.478-0.478-1.135-0.742-1.805-0.723c-0.675,0.017-1.314,0.309-1.768,0.808 c-14.829,16.325-6.762,51.623-5.916,55.115L0.723,85.717C0.26,86.18,0,86.808,0,87.463c0,0.654,0.26,1.283,0.723,1.746 l8.958,8.957c0.482,0.48,1.114,0.723,1.746,0.723c0.631,0,1.264-0.24,1.745-0.723l14.865-14.864 c7.237,1.859,16.289,2.968,24.28,2.968c9.599,0,22.739-1.543,30.836-8.886c0.5-0.454,0.793-1.093,0.809-1.769 c0.018-0.676-0.245-1.328-0.723-1.805L25.08,15.648z" fill="#656565"/>
<path d="M46.557,30.345c0.482,0.482,1.114,0.723,1.746,0.723c0.632,0,1.264-0.241,1.746-0.724l18.428-18.428 c1.305-1.305,2.023-3.04,2.023-4.885c0-1.846-0.719-3.582-2.023-4.886c-1.305-1.305-3.039-2.022-4.885-2.022 c-1.845,0-3.581,0.718-4.887,2.022L40.277,20.574c-0.964,0.964-0.964,2.527,0,3.492L46.557,30.345z" fill="#656565"/>
<path d="M96.99,30.661c-1.305-1.305-3.039-2.024-4.885-2.024c-1.847,0-3.582,0.718-4.886,2.023L68.79,49.089 c-0.464,0.463-0.724,1.091-0.724,1.746s0.26,1.282,0.724,1.746l6.28,6.278c0.481,0.482,1.113,0.724,1.746,0.724 c0.631,0,1.264-0.241,1.746-0.724l18.43-18.429C99.686,37.735,99.686,33.353,96.99,30.661z" fill="#656565"/>
</g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

После

Ширина:  |  Высота:  |  Размер: 1.8 KiB

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

@ -1,10 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
export namespace contextKeys {
export const MAVEN_EXTENSION_ACTIVATED: string = "mavenExtensionActivated";
}
export namespace contextValue {
export const MAVEN_PROJECT_NODE: string = "ProjectItem";
}

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

@ -12,8 +12,8 @@ import * as url from "url";
import { commands, ExtensionContext, extensions, Progress, ProgressLocation, RelativePattern, TextDocument, Uri, window, workspace, WorkspaceFolder } from 'vscode';
import { setUserError } from "vscode-extension-telemetry-wrapper";
import * as xml2js from "xml2js";
import { MavenExplorerProvider } from "./explorer/MavenExplorerProvider";
import { MavenProjectNode } from "./explorer/model/MavenProjectNode";
import { mavenExplorerProvider } from "./explorer/MavenExplorerProvider";
import { MavenProject } from "./explorer/model/MavenProject";
import { Settings } from "./Settings";
import { VSCodeUI } from "./VSCodeUI";
@ -193,12 +193,15 @@ export namespace Utils {
}
}
export async function executeInBackground(command: string, pomfile?: string, workspaceFolder?: WorkspaceFolder): Promise<{}> {
export async function executeInBackground(command: string, pomfile?: string, workspaceFolder?: WorkspaceFolder): Promise<any> {
if (!workspaceFolder) {
workspaceFolder = pomfile && workspace.getWorkspaceFolder(Uri.file(pomfile));
}
const mvnExecutable: string = await getMaven(workspaceFolder);
const mvnString: string = wrappedWithQuotes(mvnExecutable);
// Todo with following line:
// 1. pomfile and workspacefolde = undefined, error
// 2. non-readable
const commandCwd: string = path.resolve(workspaceFolder.uri.fsPath, mvnExecutable, "..");
const fullCommand: string = [
@ -213,14 +216,14 @@ export namespace Utils {
cwd: commandCwd,
env: Object.assign({}, process.env, customEnv)
};
return new Promise<{}>((resolve: (value: {}) => void, reject: (e: Error) => void): void => {
return new Promise<{}>((resolve: (value: any) => void, reject: (e: Error) => void): void => {
VSCodeUI.outputChannel.appendLine(fullCommand, "Background Command");
child_process.exec(fullCommand, execOptions, (error: Error, stdout: string, _stderr: string): void => {
if (error) {
VSCodeUI.outputChannel.appendLine(error);
reject(error);
} else {
resolve({ stdout });
resolve(stdout);
}
});
});
@ -310,27 +313,49 @@ export namespace Utils {
}
export async function showEffectivePom(pomPath: string): Promise<void> {
const outputPath: string = Utils.getEffectivePomOutputPath(pomPath);
await window.withProgress({ location: ProgressLocation.Window }, (p: Progress<{ message?: string }>) => new Promise<string>(
const pomxml: string = await window.withProgress({ location: ProgressLocation.Window }, (p: Progress<{ message?: string }>) => new Promise<string>(
async (resolve, reject): Promise<void> => {
p.report({ message: "Generating effective pom ... " });
try {
await Utils.executeInBackground(`help:effective-pom -Doutput="${outputPath}"`, pomPath);
resolve();
return resolve(Utils.getEffectivePom(pomPath));
} catch (error) {
setUserError(error);
reject(error);
return reject(error);
}
}
));
const pomxml: string = await Utils.readFileIfExists(outputPath);
fse.remove(outputPath);
if (pomxml) {
const document: TextDocument = await workspace.openTextDocument({ language: "xml", content: pomxml });
window.showTextDocument(document);
}
}
export async function getEffectivePom(pomPath: string): Promise<string> {
const outputPath: string = Utils.getEffectivePomOutputPath(pomPath);
try {
await Utils.executeInBackground(`help:effective-pom -Doutput="${outputPath}"`, pomPath);
const pomxml: string = await Utils.readFileIfExists(outputPath);
fse.remove(outputPath);
return pomxml;
} catch (error) {
setUserError(error);
return Promise.reject(error);
}
}
export async function getPluginDescription(pluginId: string, pomPath: string): Promise<string> {
const outputPath: string = path.join(os.tmpdir(), EXTENSION_NAME, md5(pomPath), pluginId);
try {
await Utils.executeInBackground(`help:describe -Dplugin=${pluginId} -Doutput="${outputPath}"`, pomPath);
const content: string = await Utils.readFileIfExists(outputPath);
fse.remove(outputPath);
return content;
} catch (error) {
setUserError(error);
return Promise.reject(error);
}
}
export async function excuteCustomGoal(pomPath: string): Promise<void> {
if (!pomPath) {
return;
@ -360,11 +385,11 @@ export namespace Utils {
}
}
export async function executeMavenCommand(provider: MavenExplorerProvider): Promise<void> {
export async function executeMavenCommand(): Promise<void> {
// select a project(pomfile)
const item: MavenProjectNode = await VSCodeUI.getQuickPick<MavenProjectNode>(
provider.mavenProjectNodes,
node => `$(primitive-dot) ${node.mavenProject.name}`,
const item: MavenProject = await VSCodeUI.getQuickPick<MavenProject>(
mavenExplorerProvider.mavenProjectNodes,
node => `$(primitive-dot) ${node.name}`,
null,
node => node.pomPath,
{ placeHolder: "Select a Maven project." }

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

@ -3,31 +3,34 @@
import { TreeDataProvider } from "vscode";
import * as vscode from "vscode";
import { MavenProjectNode } from "./model/MavenProjectNode";
import { NodeBase } from "./model/NodeBase";
import { WorkspaceFolderNode } from "./model/WorkspaceFolderNode";
import { ITreeItem } from "./model/ITreeItem";
import { MavenProject } from "./model/MavenProject";
import { WorkspaceFolder } from "./model/WorkspaceFolder";
export class MavenExplorerProvider implements TreeDataProvider<NodeBase> {
public readonly onDidChangeTreeData: vscode.Event<NodeBase>;
private _onDidChangeTreeData: vscode.EventEmitter<NodeBase>;
class MavenExplorerProvider implements TreeDataProvider<ITreeItem> {
public readonly onDidChangeTreeData: vscode.Event<ITreeItem>;
private _onDidChangeTreeData: vscode.EventEmitter<ITreeItem>;
private _workspaceFolderNodes: WorkspaceFolderNode[];
private _workspaceFolderNodes: WorkspaceFolder[];
constructor() {
this._onDidChangeTreeData = new vscode.EventEmitter<NodeBase>();
this._onDidChangeTreeData = new vscode.EventEmitter<ITreeItem>();
this.onDidChangeTreeData = this._onDidChangeTreeData.event;
this.refresh();
}
public get mavenProjectNodes(): MavenProjectNode[] {
public get mavenProjectNodes(): MavenProject[] {
return Array.prototype.concat.apply([], this._workspaceFolderNodes.map(ws => ws.children));
}
public getTreeItem(element: NodeBase): vscode.TreeItem | Thenable<vscode.TreeItem> {
return element.getTreeItem();
public getTreeItem(element: ITreeItem): vscode.TreeItem | Thenable<vscode.TreeItem> {
return Promise.resolve(element.getTreeItem()).then(item => {
item.contextValue = element.getContextValue();
return item;
});
}
public getChildren(element?: NodeBase): vscode.ProviderResult<NodeBase[]> {
public getChildren(element?: ITreeItem): vscode.ProviderResult<ITreeItem[]> {
if (element === undefined) {
return this._workspaceFolderNodes;
} else {
@ -42,7 +45,10 @@ export class MavenExplorerProvider implements TreeDataProvider<NodeBase> {
private _updateWorkspaceFolderNodes(): void {
this._workspaceFolderNodes = vscode.workspace.workspaceFolders ?
vscode.workspace.workspaceFolders.map(workspaceFolder => new WorkspaceFolderNode(workspaceFolder)) :
vscode.workspace.workspaceFolders.map(workspaceFolder => new WorkspaceFolder(workspaceFolder)) :
[];
}
}
// tslint:disable-next-line:export-name
export const mavenExplorerProvider: MavenExplorerProvider = new MavenExplorerProvider();

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

@ -0,0 +1,9 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
import * as vscode from "vscode";
export interface ITreeItem {
getContextValue(): string;
getTreeItem(): vscode.TreeItem | Thenable<vscode.TreeItem>;
getChildren(): vscode.ProviderResult<ITreeItem[]>;
}

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

@ -0,0 +1,91 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
import * as vscode from "vscode";
import { Utils } from "../../Utils";
import { ITreeItem } from "./ITreeItem";
import { MavenProject } from "./MavenProject";
import { PluginGoal } from "./PluginGoal";
const CONTEXT_VALUE: string = "MavenPlugin";
export class MavenPlugin implements ITreeItem {
public project: MavenProject;
public groupId: string;
public artifactId: string;
public version: string;
public prefix: string;
public goals: string[];
constructor(project: MavenProject, groupId: string, artifactId: string, version?: string) {
this.project = project;
this.groupId = groupId;
this.artifactId = artifactId;
this.version = version;
}
public getContextValue(): string {
return CONTEXT_VALUE;
}
public async getTreeItem(): Promise<vscode.TreeItem> {
const treeItem: vscode.TreeItem = new vscode.TreeItem(this.pluginId, vscode.TreeItemCollapsibleState.Collapsed);
treeItem.iconPath = {
light: Utils.getResourcePath("light/plugin.svg"),
dark: Utils.getResourcePath("dark/plugin.svg")
};
return treeItem;
}
public async getChildren(): Promise<PluginGoal[]> {
try {
await this.loadMetadata();
} catch (error) {
return [];
}
return this.goals.map(goal => new PluginGoal(this, goal));
}
private async loadMetadata(): Promise<void> {
if (this.prefix !== undefined && this.goals !== undefined) {
return;
}
const rawOutput: string = await Utils.getPluginDescription(this.pluginId, this.project.pomPath);
// find version
if (this.version === undefined) {
const versionRegExp: RegExp = /^Version: (.*)/m;
const versionMatch: string[] = rawOutput.match(versionRegExp);
if (versionMatch && versionMatch.length === 2) {
this.version = versionMatch[1];
}
}
// find prefix
const prefixRegExp: RegExp = /^Goal Prefix: (.*)/m;
const prefixMatch: string[] = rawOutput.match(prefixRegExp);
if (prefixMatch && prefixMatch.length === 2) {
this.prefix = prefixMatch[1];
}
// find goals
if (this.version && this.prefix) {
const goalRegExp: RegExp = new RegExp(`^${this.prefix}:(.*)`, "gm");
const goals: string[] = rawOutput.match(goalRegExp);
if (goals) {
this.goals = goals || [];
}
} else {
this.goals = [];
}
}
private get pluginId(): string {
let pluginId: string = `${this.groupId}:${this.artifactId}`;
if (this.version !== undefined) {
pluginId += `:${this.version}`;
}
return pluginId;
}
}

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

@ -1,30 +1,139 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
export class MavenProject {
import * as _ from "lodash";
import * as path from "path";
import * as vscode from "vscode";
import { Utils } from "../../Utils";
import { ITreeItem } from "./ITreeItem";
import { MavenPlugin } from "./MavenPlugin";
import { ModulesMenu } from "./ModulesMenu";
import { PluginsMenu } from "./PluginsMenu";
const CONTEXT_VALUE: string = "MavenProject";
export class MavenProject implements ITreeItem {
private _rawEffectivePom: string;
private _effectivePom: any;
private _pom: any;
private _pomPath: string;
get name(): string {
let ret: string;
try {
ret = this._pom.project.artifactId[0];
} catch (error) {
// ignore it
constructor(pomPath: string) {
this._pomPath = pomPath;
this.calculateEffectivePom();
}
public get name(): string {
return _.get(this._pom, "project.artifactId[0]");
}
public get moduleNames(): string[] {
return _.get(this._pom, "project.modules[0].module") || [];
}
public async plugins(): Promise<MavenPlugin[]> {
let plugins: any[];
await this.calculateEffectivePom();
if (_.get(this._effectivePom, "projects.project")) {
// multi-module project
const project: any = (<any[]>this._effectivePom.projects.project).find((elem: any) => this.name === _.get(elem, "artifactId[0]"));
if (project) {
plugins = _.get(project, "build[0].plugins[0].plugin");
}
} else {
// single-project
plugins = _.get(this._effectivePom, "project.build[0].plugins[0].plugin");
}
return this.convertXmlPlugin(plugins);
}
/**
* @return list of absolute path of modules pom.xml.
*/
public get modules(): string[] {
return this.moduleNames.map(moduleName => path.join(path.dirname(this._pomPath), moduleName, "pom.xml"));
}
public get pomPath(): string {
return this._pomPath;
}
public async getTreeItem(): Promise<vscode.TreeItem> {
if (! await this.hasValidPom()) {
return undefined;
}
const treeItem: vscode.TreeItem = new vscode.TreeItem(this.name);
treeItem.iconPath = {
light: Utils.getResourcePath("project.svg"),
dark: Utils.getResourcePath("project.svg")
};
treeItem.collapsibleState = vscode.TreeItemCollapsibleState.Collapsed;
treeItem.command = { title: "open pom", command: "maven.project.openPom", arguments: [this] };
return treeItem;
}
public getContextValue(): string {
return CONTEXT_VALUE;
}
public getChildren(): vscode.ProviderResult<ITreeItem[]> {
const ret: ITreeItem[] = [];
if (this._hasModules) {
ret.push(new ModulesMenu(this));
}
ret.push(new PluginsMenu(this));
return ret;
}
get modules(): string[] {
let ret: string[] = [];
try {
ret = this._pom.project.modules[0].module;
} catch (error) {
// ignore it
}
return ret;
public async hasValidPom(): Promise<boolean> {
await this._parsePom();
return !!this._pom;
}
constructor(pom: any) {
this._pom = pom;
public async calculateEffectivePom(force?: boolean): Promise<void> {
if (!force && this._rawEffectivePom) {
return;
}
this._rawEffectivePom = await Utils.getEffectivePom(this._pomPath);
await this._parseEffectivePom();
}
private get _hasModules(): boolean {
return this.moduleNames.length > 0;
}
private async _parsePom(): Promise<void> {
if (!this._pom) {
try {
this._pom = await Utils.parseXmlFile(this._pomPath);
} catch (error) {
// Error parsing pom.xml file
}
}
}
private async _parseEffectivePom(): Promise<void> {
if (!this._effectivePom) {
try {
this._effectivePom = await Utils.parseXmlContent(this._rawEffectivePom);
} catch (error) {
// Error parsing pom.xml file
}
}
}
private convertXmlPlugin(plugins: any[]): MavenPlugin[] {
if (plugins && plugins.length > 0) {
return plugins.map(p => new MavenPlugin(
this,
_.get(p, "groupId[0]") || "org.apache.maven.plugins",
_.get(p, "artifactId[0]"),
_.get(p, "version[0]")
));
}
return [];
}
}

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

@ -1,74 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
import * as path from "path";
import * as vscode from "vscode";
import * as Constants from "../../Constants";
import { Utils } from "../../Utils";
import { MavenProject } from "./MavenProject";
import { ModulesMenuNode } from "./ModulesMenuNode";
import { NodeBase } from "./NodeBase";
export class MavenProjectNode extends NodeBase {
private _mavenProject: MavenProject;
private _pomPath: string;
constructor(pomPath: string) {
super();
this._pomPath = pomPath;
}
public async getTreeItem(): Promise<vscode.TreeItem> {
if (! await this.hasValidPom()) {
return undefined;
}
const treeItem: vscode.TreeItem = new vscode.TreeItem(this._mavenProject.name);
treeItem.iconPath = {
light: Utils.getResourcePath("project.svg"),
dark: Utils.getResourcePath("project.svg")
};
treeItem.contextValue = Constants.contextValue.MAVEN_PROJECT_NODE;
treeItem.collapsibleState = this._hasModules ? vscode.TreeItemCollapsibleState.Collapsed : vscode.TreeItemCollapsibleState.None;
treeItem.command = { title: "open pom", command: "maven.project.openPom", arguments: [this] };
return treeItem;
}
public getChildren(): vscode.ProviderResult<NodeBase[]> {
return this._hasModules ? [new ModulesMenuNode(this)] : [];
}
/**
* @return list of absolute path of modules pom.xml.
*/
public get modules(): string[] {
return this._mavenProject.modules.map(moduleName => path.join(path.dirname(this._pomPath), moduleName, "pom.xml"));
}
public get pomPath(): string {
return this._pomPath;
}
public get mavenProject(): MavenProject {
return this._mavenProject;
}
public async hasValidPom(): Promise<boolean> {
await this._parseMavenProject();
return !!this._mavenProject;
}
private get _hasModules(): boolean {
return this._mavenProject.modules.length > 0;
}
private async _parseMavenProject(): Promise<void> {
if (!this._mavenProject) {
try {
const pom: {} = await Utils.parseXmlFile(this._pomPath);
this._mavenProject = new MavenProject(pom);
} catch (error) {
// Error parsing pom.xml file
}
}
}
}

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

@ -3,17 +3,25 @@
import * as vscode from "vscode";
import { Utils } from "../../Utils";
import { MavenProjectNode } from "./MavenProjectNode";
import { NodeBase } from "./NodeBase";
import { ITreeItem } from "./ITreeItem";
import { MavenProject } from "./MavenProject";
export abstract class MenuNode extends NodeBase {
protected _projectNode: MavenProjectNode;
const CONTEXT_VALUE: string = "Menu";
export abstract class Menu implements ITreeItem {
protected _project: MavenProject;
protected _name: string;
constructor(projectNode: MavenProjectNode) {
super();
this._projectNode = projectNode;
constructor(project: MavenProject) {
this._project = project;
}
public abstract getChildren(): vscode.ProviderResult<ITreeItem[]>;
public getContextValue(): string {
return CONTEXT_VALUE;
}
public getTreeItem(): vscode.TreeItem | Thenable<vscode.TreeItem> {
const treeItem: vscode.TreeItem = new vscode.TreeItem(this._name, vscode.TreeItemCollapsibleState.Collapsed);
treeItem.iconPath = {

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

@ -0,0 +1,17 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
import { ITreeItem } from "./ITreeItem";
import { MavenProject } from "./MavenProject";
import { Menu } from "./Menu";
export class ModulesMenu extends Menu implements ITreeItem {
constructor(projectNode: MavenProject) {
super(projectNode);
this._name = "Modules";
}
public getChildren() : MavenProject[] {
return this._project.modules.map(modulePomPath => new MavenProject(modulePomPath));
}
}

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

@ -1,16 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
import { MavenProjectNode } from "./MavenProjectNode";
import { MenuNode } from "./MenuNode";
export class ModulesMenuNode extends MenuNode {
constructor(projectNode: MavenProjectNode) {
super(projectNode);
this._name = "Modules";
}
public getChildren() : MavenProjectNode[] {
return this._projectNode.modules.map(modulePomPath => new MavenProjectNode(modulePomPath));
}
}

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

@ -1,8 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
import * as vscode from "vscode";
export abstract class NodeBase {
public abstract getTreeItem(): vscode.TreeItem | Thenable<vscode.TreeItem>;
public abstract getChildren(): vscode.ProviderResult<NodeBase[]>;
}

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

@ -0,0 +1,27 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
import * as vscode from "vscode";
import { ITreeItem } from "./ITreeItem";
import { MavenPlugin } from "./MavenPlugin";
export class PluginGoal implements ITreeItem {
public plugin: MavenPlugin;
public name: string;
constructor(plugin: MavenPlugin, name: string) {
this.plugin = plugin;
this.name = name;
}
public getContextValue(): string {
return "PluginGoal";
}
public getTreeItem(): vscode.TreeItem {
return new vscode.TreeItem(this.name, vscode.TreeItemCollapsibleState.None);
}
public getChildren(): ITreeItem[] {
return null;
}
}

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

@ -0,0 +1,18 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
import { ITreeItem } from "./ITreeItem";
import { MavenPlugin } from "./MavenPlugin";
import { MavenProject } from "./MavenProject";
import { Menu } from "./Menu";
export class PluginsMenu extends Menu implements ITreeItem {
constructor(project: MavenProject) {
super(project);
this._name = "Plugins";
}
public async getChildren() : Promise<MavenPlugin[]> {
return await this._project.plugins();
}
}

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

@ -4,16 +4,17 @@
import * as vscode from "vscode";
import { TreeItemCollapsibleState } from "vscode";
import { Utils } from "../../Utils";
import { MavenProjectNode } from "./MavenProjectNode";
import { NodeBase } from "./NodeBase";
import { ITreeItem } from "./ITreeItem";
import { MavenProject } from "./MavenProject";
export class WorkspaceFolderNode extends NodeBase {
const CONTEXT_VALUE: string = "WorkspaceFolder";
export class WorkspaceFolder implements ITreeItem {
private _workspaceFolder: vscode.WorkspaceFolder;
private _pomPaths: string[];
private _children: MavenProjectNode[];
private _children: MavenProject[];
constructor(workspaceFolder: vscode.WorkspaceFolder) {
super();
this._workspaceFolder = workspaceFolder;
this._children = [];
}
@ -22,18 +23,22 @@ export class WorkspaceFolderNode extends NodeBase {
return this._pomPaths;
}
public get children(): MavenProjectNode[] {
public get children(): MavenProject[] {
return this._children;
}
public async getChildren(): Promise<NodeBase[]> {
public getContextValue(): string {
return CONTEXT_VALUE;
}
public async getChildren(): Promise<ITreeItem[]> {
await this._searchForPomPaths();
this._children = [];
for ( const pomPath of this._pomPaths ) {
const projectNode: MavenProjectNode = new MavenProjectNode(pomPath);
for (const pomPath of this._pomPaths) {
const projectNode: MavenProject = new MavenProject(pomPath);
if ( await projectNode.hasValidPom() ) {
if (await projectNode.hasValidPom()) {
this._children.push(projectNode);
}
}
@ -51,8 +56,8 @@ export class WorkspaceFolderNode extends NodeBase {
}
private _sortChildren(): void {
this._children.sort( (a, b) => {
return a.mavenProject.name > b.mavenProject.name ? 1 : a.mavenProject.name < b.mavenProject.name ? -1 : 0;
} );
this._children.sort((a, b) => {
return a.name > b.name ? 1 : a.name < b.name ? -1 : 0;
});
}
}

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

@ -7,8 +7,9 @@ import { Progress, Uri } from "vscode";
import { dispose as disposeTelemetryWrapper, initializeFromJsonFile, instrumentOperation, TelemetryWrapper } from "vscode-extension-telemetry-wrapper";
import { ArchetypeModule } from "./archetype/ArchetypeModule";
import { OperationCanceledError } from "./Errors";
import { MavenExplorerProvider } from "./explorer/MavenExplorerProvider";
import { MavenProjectNode } from "./explorer/model/MavenProjectNode";
import { mavenExplorerProvider } from "./explorer/MavenExplorerProvider";
import { MavenProject } from "./explorer/model/MavenProject";
import { PluginGoal } from "./explorer/model/PluginGoal";
import { Settings } from "./Settings";
import { Utils } from "./Utils";
import { VSCodeUI } from "./VSCodeUI";
@ -47,42 +48,42 @@ function registerCommand(context: vscode.ExtensionContext, commandName: string,
async function doActivate(_operationId: string, context: vscode.ExtensionContext): Promise<void> {
await vscode.commands.executeCommand("setContext", "mavenExtensionActivated", true);
const provider: MavenExplorerProvider = new MavenExplorerProvider();
context.subscriptions.push(vscode.window.registerTreeDataProvider("mavenProjects", provider));
context.subscriptions.push(vscode.window.registerTreeDataProvider("mavenProjects", mavenExplorerProvider));
// pom.xml listener to refresh tree view
const watcher: vscode.FileSystemWatcher = vscode.workspace.createFileSystemWatcher("**/pom.xml");
watcher.onDidCreate(() => provider.refresh());
watcher.onDidChange(() => provider.refresh());
watcher.onDidDelete(() => provider.refresh());
watcher.onDidCreate(() => mavenExplorerProvider.refresh());
watcher.onDidChange(() => mavenExplorerProvider.refresh());
watcher.onDidDelete(() => mavenExplorerProvider.refresh());
context.subscriptions.push(watcher);
// register commands.
["clean", "validate", "compile", "test", "package", "verify", "install", "site", "deploy"].forEach((goal: string) => {
registerCommand(context, `maven.goal.${goal}`, async (node: MavenProjectNode) => {
registerCommand(context, `maven.goal.${goal}`, async (node: MavenProject) => {
Utils.executeInTerminal(goal, node.pomPath);
});
});
registerCommand(context, "maven.project.refreshAll", (): void => {
provider.refresh();
mavenExplorerProvider.refresh();
});
registerCommand(context, "maven.project.effectivePom", async (node: Uri | MavenProjectNode) => {
registerCommand(context, "maven.project.effectivePom", async (node: Uri | MavenProject) => {
if (node instanceof Uri && node.fsPath) {
await Utils.showEffectivePom(node.fsPath);
} else if (node instanceof MavenProjectNode && node.pomPath) {
} else if (node instanceof MavenProject && node.pomPath) {
await Utils.showEffectivePom(node.pomPath);
}
});
registerCommand(context, "maven.goal.custom", async (node: MavenProjectNode) => {
registerCommand(context, "maven.goal.custom", async (node: MavenProject) => {
if (node && node.pomPath) {
await Utils.excuteCustomGoal(node.pomPath);
}
});
registerCommand(context, "maven.project.openPom", async (node: MavenProjectNode) => {
registerCommand(context, "maven.project.openPom", async (node: MavenProject) => {
if (node && node.pomPath) {
await VSCodeUI.openFileIfExists(node.pomPath);
}
@ -90,7 +91,7 @@ async function doActivate(_operationId: string, context: vscode.ExtensionContext
registerCommand(context, "maven.archetype.generate", async (operationId: string, entry: Uri | undefined) => {
await ArchetypeModule.generateFromArchetype(entry, operationId);
}, true);
}, true);
registerCommand(context, "maven.archetype.update", async () => {
await vscode.window.withProgress({ location: vscode.ProgressLocation.Window }, async (p: Progress<{}>) => {
@ -100,16 +101,24 @@ async function doActivate(_operationId: string, context: vscode.ExtensionContext
});
});
registerCommand(context, "maven.history", async (item: MavenProjectNode | undefined) => {
registerCommand(context, "maven.history", async (item: MavenProject | undefined) => {
if (item) {
await Utils.executeHistoricalGoals([item.pomPath]);
} else {
await Utils.executeHistoricalGoals(provider.mavenProjectNodes.map(_node => _node.pomPath));
await Utils.executeHistoricalGoals(mavenExplorerProvider.mavenProjectNodes.map(_node => _node.pomPath));
}
});
registerCommand(context, "maven.goal.execute", async () => {
await Utils.executeMavenCommand(provider);
await Utils.executeMavenCommand();
});
registerCommand(context, "maven.plugin.execute", async (node: PluginGoal) => {
if (node &&
node.name &&
node.plugin && node.plugin.project && node.plugin.project.pomPath) {
Utils.executeInTerminal(node.name, node.plugin.project.pomPath);
}
});
context.subscriptions.push(vscode.window.onDidCloseTerminal((closedTerminal: vscode.Terminal) => {
@ -131,6 +140,6 @@ async function doActivate(_operationId: string, context: vscode.ExtensionContext
// workspace folder change listener
vscode.workspace.onDidChangeWorkspaceFolders((_e: vscode.WorkspaceFoldersChangeEvent) => {
provider.refresh();
mavenExplorerProvider.refresh();
});
}

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

@ -217,7 +217,6 @@
"align": [
true,
"parameters",
"arguments",
"statements"
],
"curly": true,
@ -296,4 +295,4 @@
},
"rulesDirectory": "node_modules/tslint-microsoft-contrib/",
"defaultSeverity": "warning"
}
}