blob: dd7f9374aab5a7fee508ba587c2907b2be81ba94 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011 Sonatype, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Sonatype, Inc. - initial API and implementation
* Andrew Eisenberg - adapted for workspace preferences
*******************************************************************************/
package org.eclipse.m2e.core.ui.internal.preferences;
import java.io.IOException;
import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.osgi.framework.Bundle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.ToolBarManager;
import org.eclipse.jface.viewers.AbstractTreeViewer;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.TreeViewerColumn;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn;
import org.eclipse.ui.PlatformUI;
import org.codehaus.plexus.util.xml.Xpp3Dom;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.plugin.MojoExecution;
import org.apache.maven.project.MavenProject;
import org.eclipse.m2e.core.MavenPlugin;
import org.eclipse.m2e.core.internal.lifecyclemapping.LifecycleMappingFactory;
import org.eclipse.m2e.core.internal.lifecyclemapping.LifecycleMappingResult;
import org.eclipse.m2e.core.internal.lifecyclemapping.model.LifecycleMappingMetadata;
import org.eclipse.m2e.core.internal.lifecyclemapping.model.LifecycleMappingMetadataSource;
import org.eclipse.m2e.core.internal.lifecyclemapping.model.PluginExecutionFilter;
import org.eclipse.m2e.core.internal.lifecyclemapping.model.PluginExecutionMetadata;
import org.eclipse.m2e.core.internal.lifecyclemapping.model.io.xpp3.LifecycleMappingMetadataSourceXpp3Writer;
import org.eclipse.m2e.core.internal.project.registry.MavenProjectFacade;
import org.eclipse.m2e.core.lifecyclemapping.model.IPluginExecutionMetadata;
import org.eclipse.m2e.core.lifecyclemapping.model.PluginExecutionAction;
import org.eclipse.m2e.core.project.IMavenProjectFacade;
import org.eclipse.m2e.core.project.IMavenProjectRegistry;
import org.eclipse.m2e.core.project.configurator.MojoExecutionKey;
import org.eclipse.m2e.core.ui.internal.MavenImages;
import org.eclipse.m2e.core.ui.internal.Messages;
@SuppressWarnings("restriction")
class LifecycleMappingsViewer {
private static final Logger log = LoggerFactory.getLogger(LifecycleMappingsViewer.class);
/*package*/TreeViewer mappingsTreeViewer;
/*package*/boolean showPhases = false;
/*package*/boolean showIgnoredExecutions = true;
/*package*/Map<MojoExecutionKey, List<IPluginExecutionMetadata>> mappings;
/*package*/Map<String, List<MojoExecutionKey>> phases;
private Shell shell;
void updateMappingsTreeViewer() {
mappingsTreeViewer.refresh();
if(showPhases) {
// reveal non-empty mappings
mappingsTreeViewer.collapseAll();
for(Map.Entry<MojoExecutionKey, List<IPluginExecutionMetadata>> entry : mappings.entrySet()) {
boolean expand = false;
if(isErrorMapping(entry.getKey())) {
expand = true;
} else {
expand = !isIgnoreMapping(entry.getKey(), entry.getValue());
}
if(expand) {
mappingsTreeViewer.expandToLevel(entry.getKey().getLifecyclePhase(), AbstractTreeViewer.ALL_LEVELS);
}
}
}
// auto-size all columns
for(TreeColumn column : mappingsTreeViewer.getTree().getColumns()) {
column.pack();
}
}
/**
* @wbp.parser.entryPoint
*/
public Composite createContents(Composite parent) {
Composite container = new Composite(parent, SWT.NULL);
GridLayout gl_container = new GridLayout(1, false);
gl_container.marginWidth = 0;
gl_container.marginHeight = 0;
container.setLayout(gl_container);
Composite optionsComposit = new Composite(container, SWT.NONE);
GridLayout gl_optionsComposit = new GridLayout(3, false);
gl_optionsComposit.marginWidth = 0;
gl_optionsComposit.marginHeight = 0;
optionsComposit.setLayout(gl_optionsComposit);
optionsComposit.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
final Button btnShowPhases = new Button(optionsComposit, SWT.CHECK);
btnShowPhases.setSelection(showPhases);
btnShowPhases.setText(Messages.LifecycleMappingPropertyPage_showLIfecyclePhases);
final Button btnShowIgnored = new Button(optionsComposit, SWT.CHECK);
btnShowIgnored.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
showIgnoredExecutions = btnShowIgnored.getSelection();
updateMappingsTreeViewer();
}
});
btnShowIgnored.setSelection(showIgnoredExecutions);
btnShowIgnored.setText(Messages.LifecycleMappingPropertyPage_mntmShowIgnoredExecutions_text);
final Action actExpandAll = new Action(Messages.LifecycleMappingPropertyPage_mntmExpandAll_text,
MavenImages.EXPANDALL) {
public void run() {
mappingsTreeViewer.expandAll();
};
};
actExpandAll.setEnabled(showPhases);
final Action actCollapseAll = new Action(Messages.LifecycleMappingPropertyPage_mntmCollapseAll_text,
MavenImages.COLLAPSEALL) {
public void run() {
mappingsTreeViewer.collapseAll();
};
};
actCollapseAll.setEnabled(showPhases);
Composite toolbarComposite = new Composite(optionsComposit, SWT.NONE);
toolbarComposite.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, true, false, 1, 1));
GridLayout gl_toolbarComposite = new GridLayout(1, false);
gl_toolbarComposite.marginWidth = 0;
gl_toolbarComposite.marginHeight = 0;
toolbarComposite.setLayout(gl_toolbarComposite);
ToolBar toolBar = new ToolBar(toolbarComposite, SWT.FLAT | SWT.RIGHT);
ToolBarManager toolBarManager = new ToolBarManager(toolBar);
toolBarManager.add(actExpandAll);
toolBarManager.add(actCollapseAll);
toolBarManager.update(true);
btnShowPhases.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
showPhases = btnShowPhases.getSelection();
actExpandAll.setEnabled(showPhases);
actCollapseAll.setEnabled(showPhases);
updateMappingsTreeViewer();
}
});
mappingsTreeViewer = new TreeViewer(container, SWT.BORDER);
Tree tree = mappingsTreeViewer.getTree();
tree.setHeaderVisible(true);
tree.setLinesVisible(true);
tree.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
TreeViewerColumn treeViewerColumn = new TreeViewerColumn(mappingsTreeViewer, SWT.NONE);
TreeColumn trclmnGoal = treeViewerColumn.getColumn();
trclmnGoal.setWidth(100);
trclmnGoal.setText(Messages.LifecycleMappingPropertyPage_pluginExecution);
TreeViewerColumn treeViewerColumn_1 = new TreeViewerColumn(mappingsTreeViewer, SWT.NONE);
TreeColumn trclmnNewColumn = treeViewerColumn_1.getColumn();
trclmnNewColumn.setWidth(100);
trclmnNewColumn.setText(Messages.LifecycleMappingPropertyPage_mapping);
TreeViewerColumn treeViewerColumn_2 = new TreeViewerColumn(mappingsTreeViewer, SWT.NONE);
TreeColumn trclmnSource = treeViewerColumn_2.getColumn();
trclmnSource.setWidth(100);
trclmnSource.setText(Messages.LifecycleMappingsViewer_trclmnSource_text);
mappingsTreeViewer.setContentProvider(new ITreeContentProvider() {
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
}
public void dispose() {
}
public boolean hasChildren(Object element) {
return getChildren(element) != null;
}
public Object getParent(Object element) {
return null;
}
public Object[] getElements(Object inputElement) {
if(showPhases) {
return phases.keySet().toArray();
}
Set<MojoExecutionKey> executions;
if(showIgnoredExecutions) {
executions = mappings.keySet();
} else {
executions = new LinkedHashSet<MojoExecutionKey>();
for(Map.Entry<MojoExecutionKey, List<IPluginExecutionMetadata>> entry : mappings.entrySet()) {
if(!isIgnoreMapping(entry.getKey(), entry.getValue())) {
executions.add(entry.getKey());
}
}
}
return executions.toArray();
}
public Object[] getChildren(Object parentElement) {
List<MojoExecutionKey> executions = phases.get(parentElement);
if(executions == null || executions.isEmpty()) {
return null;
}
if(showIgnoredExecutions) {
return executions.toArray();
}
// filter out ignored executions
executions = new ArrayList<MojoExecutionKey>(executions); // clone
Iterator<MojoExecutionKey> iter = executions.iterator();
while(iter.hasNext()) {
MojoExecutionKey execution = iter.next();
if(isIgnoreMapping(execution, mappings.get(execution))) {
iter.remove();
}
}
return !executions.isEmpty() ? executions.toArray() : null;
}
});
mappingsTreeViewer.setLabelProvider(new ITableLabelProvider() {
public void addListener(ILabelProviderListener listener) {
}
public void dispose() {
}
public boolean isLabelProperty(Object element, String property) {
return false;
}
public void removeListener(ILabelProviderListener listener) {
}
public Image getColumnImage(Object element, int columnIndex) {
if(columnIndex == 0 && element instanceof MojoExecutionKey) {
return isErrorMapping((MojoExecutionKey) element) ? MavenImages.IMG_ERROR : MavenImages.IMG_PASSED;
}
return null;
}
public String getColumnText(Object element, int columnIndex) {
if(element instanceof MojoExecutionKey) {
MojoExecutionKey execution = (MojoExecutionKey) element;
switch(columnIndex) {
case 0:
return LifecycleMappingsViewer.this.toString(execution);
case 1:
return LifecycleMappingsViewer.this.toString(execution, mappings.get(execution));
case 2:
return getSourcelabel(execution, mappings.get(execution), false);
}
}
return columnIndex == 0 ? element.toString() : null;
}
});
Composite actionsComposite = new Composite(container, SWT.NONE);
actionsComposite.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, true, false, 1, 1));
actionsComposite.setLayout(new RowLayout(SWT.HORIZONTAL));
Button btnCopyToClipboard = new Button(actionsComposite, SWT.NONE);
btnCopyToClipboard.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
copyToClipboard();
}
});
btnCopyToClipboard.setText(Messages.LifecycleMappingPropertyPage_copyToClipboard);
mappingsTreeViewer.setInput(phases);
updateMappingsTreeViewer();
return container;
}
void copyToClipboard() {
if(mappings == null) {
return;
}
LifecycleMappingMetadata meta = new LifecycleMappingMetadata();
for(Map.Entry<MojoExecutionKey, List<IPluginExecutionMetadata>> entry : this.mappings.entrySet()) {
MojoExecutionKey execution = entry.getKey();
List<IPluginExecutionMetadata> mappings = entry.getValue();
if(mappings != null && !mappings.isEmpty()) {
for(IPluginExecutionMetadata mapping : mappings) {
PluginExecutionMetadata clone = ((PluginExecutionMetadata) mapping).clone();
setMappingSource(execution, mappings, clone);
meta.addPluginExecution(clone);
}
} else {
PluginExecutionFilter filter = new PluginExecutionFilter(execution.getGroupId(), execution.getArtifactId(),
execution.getVersion(), execution.getGoal());
PluginExecutionMetadata mapping = new PluginExecutionMetadata();
mapping.setFilter(filter);
Xpp3Dom actionDom;
if(LifecycleMappingFactory.isInterestingPhase(entry.getKey().getLifecyclePhase())) {
actionDom = new Xpp3Dom(PluginExecutionAction.error.toString());
} else {
actionDom = new Xpp3Dom(PluginExecutionAction.ignore.toString());
}
mapping.setActionDom(actionDom);
setMappingSource(execution, mappings, mapping);
meta.addPluginExecution(mapping);
}
}
LifecycleMappingMetadataSource xml = new LifecycleMappingMetadataSource();
xml.addLifecycleMapping(meta);
StringWriter buf = new StringWriter();
try {
new LifecycleMappingMetadataSourceXpp3Writer().write(buf, xml);
Clipboard clipboard = new Clipboard(shell.getDisplay());
Object[] data = new Object[] {buf.toString()};
Transfer[] dataTypes = new Transfer[] {TextTransfer.getInstance()};
clipboard.setContents(data, dataTypes);
clipboard.dispose();
} catch(IOException ex) {
// TODO log
}
}
private void setMappingSource(MojoExecutionKey execution, List<IPluginExecutionMetadata> mappings,
PluginExecutionMetadata clone) {
clone.setComment("source: " + getSourcelabel(execution, mappings, true)); //$NON-NLS-1$
}
boolean isErrorMapping(MojoExecutionKey execution) {
List<IPluginExecutionMetadata> mappings = this.mappings.get(execution);
if(mappings == null || mappings.isEmpty()) {
return LifecycleMappingFactory.isInterestingPhase(execution.getLifecyclePhase());
}
for(IPluginExecutionMetadata mapping : mappings) {
if(PluginExecutionAction.error == mapping.getAction()) {
return true;
}
}
return false;
}
boolean isIgnoreMapping(MojoExecutionKey execution, List<IPluginExecutionMetadata> mappings) {
if(mappings == null || mappings.isEmpty()) {
return !LifecycleMappingFactory.isInterestingPhase(execution.getLifecyclePhase());
}
for(IPluginExecutionMetadata mapping : mappings) {
if(PluginExecutionAction.ignore != mapping.getAction()) {
return false;
}
}
return true;
}
String toString(MojoExecutionKey execution, List<IPluginExecutionMetadata> mappings) {
StringBuilder sb = new StringBuilder();
if(mappings != null && !mappings.isEmpty()) {
for(IPluginExecutionMetadata mapping : mappings) {
if(sb.length() > 0) {
sb.append(',');
}
sb.append(mapping.getAction().toString());
}
} else {
if(LifecycleMappingFactory.isInterestingPhase(execution.getLifecyclePhase())) {
sb.append(PluginExecutionAction.error.toString());
} else {
sb.append(PluginExecutionAction.ignore.toString());
}
}
return sb.toString();
}
String getSourcelabel(MojoExecutionKey execution, List<IPluginExecutionMetadata> mappings, boolean detailed) {
LinkedHashSet<String> sources = new LinkedHashSet<String>();
if(mappings != null && !mappings.isEmpty()) {
for(IPluginExecutionMetadata mapping : mappings) {
LifecycleMappingMetadataSource metadata = ((PluginExecutionMetadata) mapping).getSource();
if(metadata != null) {
Object source = metadata.getSource();
if(source instanceof String) {
sources.add((String) source);
} else if(source instanceof Artifact) {
sources.add(getSourceLabel((Artifact) source, detailed));
} else if(source instanceof MavenProject) {
sources.add(getSourceLabel((MavenProject) source, detailed));
} else if(source instanceof Bundle) {
sources.add(getSourceLabel((Bundle) source, detailed));
} else {
sources.add("unknown"); //$NON-NLS-1$
}
}
}
} else {
if(!LifecycleMappingFactory.isInterestingPhase(execution.getLifecyclePhase())) {
sources.add("uninteresting"); //$NON-NLS-1$
}
}
StringBuilder sb = new StringBuilder();
for(String source : sources) {
if(sb.length() > 0) {
sb.append(',');
}
sb.append(source);
}
return sb.toString();
}
private String getSourceLabel(Bundle bundle, boolean detailed) {
StringBuilder sb = new StringBuilder("extension"); //$NON-NLS-1$
if(detailed) {
sb.append('(').append(bundle.getSymbolicName()).append('_').append(bundle.getVersion()).append(')');
}
return sb.toString();
}
private String getSourceLabel(MavenProject project, boolean detailed) {
StringBuilder sb = new StringBuilder("pom"); //$NON-NLS-1$
if(detailed) {
sb.append('(').append(project.toString()).append(')');
}
return sb.toString();
}
private String getSourceLabel(Artifact plugin, boolean detailed) {
StringBuilder sb = new StringBuilder("maven-plugin"); //$NON-NLS-1$
if(detailed) {
sb.append('(').append(plugin.toString()).append(')');
}
return sb.toString();
}
String toString(MojoExecutionKey execution) {
// http://maven.apache.org/guides/plugin/guide-java-plugin-development.html#Shortening_the_Command_Line
StringBuilder sb = new StringBuilder();
// TODO show groupId, but only if not a known plugin groupId
// shorten artifactId
String artifactId = execution.getArtifactId();
if(artifactId.endsWith("-maven-plugin")) { //$NON-NLS-1$
artifactId = artifactId.substring(0, artifactId.length() - "-maven-plugin".length()); //$NON-NLS-1$
} else if(artifactId.startsWith("maven-") && artifactId.endsWith("-plugin")) { //$NON-NLS-1$ //$NON-NLS-2$
artifactId = artifactId.substring("maven-".length(), artifactId.length() - "-plugin".length()); //$NON-NLS-1$ //$NON-NLS-2$
}
sb.append(artifactId).append(':').append(execution.getGoal());
// only show execution id if necessary
int count = 0;
for(MojoExecutionKey other : mappings.keySet()) {
if(eq(execution.getGroupId(), other.getGroupId()) && eq(execution.getArtifactId(), other.getArtifactId())
&& eq(execution.getGoal(), other.getGoal())) {
count++ ;
}
}
if(count > 1) {
sb.append(" (").append(execution.getExecutionId()).append(")"); //$NON-NLS-1$ //$NON-NLS-2$
}
return sb.toString();
}
static <T> boolean eq(T a, T b) {
return a != null ? a.equals(b) : b == null;
}
public void setTarget(final IProject project) {
if(project == null) {
// TODO FIXADE find the mojo execution mapping for the workspace...How do I do this?
} else {
try {
PlatformUI.getWorkbench().getProgressService().run(false, false, monitor -> {
final IMavenProjectRegistry projectRegistry = MavenPlugin.getMavenProjectRegistry();
final IMavenProjectFacade facade = projectRegistry.getProject(project);
if(facade == null) {
return;
}
try {
projectRegistry.execute(facade, (context, monitor1) -> {
MavenProject mavenProject = facade.getMavenProject(monitor1);
List<MojoExecution> mojoExecutions = ((MavenProjectFacade) facade).getMojoExecutions(monitor1);
LifecycleMappingResult mappingResult = LifecycleMappingFactory.calculateLifecycleMapping(mavenProject,
mojoExecutions, facade.getResolverConfiguration().getLifecycleMappingId(), monitor1);
mappings = mappingResult.getMojoExecutionMapping();
return null;
}, monitor);
} catch(CoreException ex) {
throw new InvocationTargetException(ex);
}
});
} catch(InvocationTargetException ex) {
log.error(ex.getMessage(), ex);
} catch(InterruptedException ex) {
log.error(ex.getMessage(), ex);
}
}
phases = new LinkedHashMap<String, List<MojoExecutionKey>>();
if(mappings != null) {
for(MojoExecutionKey execution : mappings.keySet()) {
List<MojoExecutionKey> executions = phases.get(execution.getLifecyclePhase());
if(executions == null) {
executions = new ArrayList<MojoExecutionKey>();
phases.put(execution.getLifecyclePhase(), executions);
}
executions.add(execution);
}
}
}
/**
* @param shell
*/
public void setShell(Shell shell) {
this.shell = shell;
}
protected boolean isValid() {
return mappings != null;
}
}