diff options
author | Igor Fedorenko | 2013-01-24 04:24:23 +0000 |
---|---|---|
committer | Igor Fedorenko | 2013-02-16 16:41:50 +0000 |
commit | e03d2925e0632053312539edef7350e37783963f (patch) | |
tree | e22c59b784215ec6512729446c198f2322c3c56a | |
parent | 293a1c09ed3ec5401093b7b3b783ea161838b6f0 (diff) | |
download | m2e-core-e03d2925e0632053312539edef7350e37783963f.tar.gz m2e-core-e03d2925e0632053312539edef7350e37783963f.tar.xz m2e-core-e03d2925e0632053312539edef7350e37783963f.zip |
initial prototype of build troubleshooting view
Signed-off-by: Igor Fedorenko <igor@ifedorenko.com>
17 files changed, 732 insertions, 1 deletions
diff --git a/org.eclipse.m2e.core.ui/icons/clear.gif b/org.eclipse.m2e.core.ui/icons/clear.gif Binary files differnew file mode 100644 index 00000000..2cd9c544 --- /dev/null +++ b/org.eclipse.m2e.core.ui/icons/clear.gif diff --git a/org.eclipse.m2e.core.ui/icons/suspend.gif b/org.eclipse.m2e.core.ui/icons/suspend.gif Binary files differnew file mode 100644 index 00000000..161e3f59 --- /dev/null +++ b/org.eclipse.m2e.core.ui/icons/suspend.gif diff --git a/org.eclipse.m2e.core.ui/plugin.properties b/org.eclipse.m2e.core.ui/plugin.properties index bc485714..a3a5a5d8 100644 --- a/org.eclipse.m2e.core.ui/plugin.properties +++ b/org.eclipse.m2e.core.ui/plugin.properties @@ -94,6 +94,7 @@ action.addplugin.label = Add Maven Plugin action.add.plugin.tooltip = Add Maven Plugin category.maven.name = Maven view.repos.name = Maven Repositories +view.build.name = Maven Workspace Build page.maven.name = Maven page.mappings.name = Lifecycle Mapping lifecycleMapping.custom.name = Customizable Lifecycle Mapping diff --git a/org.eclipse.m2e.core.ui/plugin.xml b/org.eclipse.m2e.core.ui/plugin.xml index 117f86be..965e5522 100644 --- a/org.eclipse.m2e.core.ui/plugin.xml +++ b/org.eclipse.m2e.core.ui/plugin.xml @@ -485,6 +485,14 @@ class="org.eclipse.m2e.core.ui.internal.views.MavenRepositoryView" icon="icons/maven_indexes.gif" name="%view.repos.name"/> + <view + allowMultiple="false" + category="org.eclipse.m2e.core.views.repositories" + class="org.eclipse.m2e.core.ui.internal.views.build.BuildDebugView" + id="org.eclipse.m2e.core.views.MavenBuild" + name="%view.build.name" + restorable="true"> + </view> </extension> <extension point="org.eclipse.ui.bindings"> diff --git a/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/MavenImages.java b/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/MavenImages.java index 2452ae70..43a2a1cc 100644 --- a/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/MavenImages.java +++ b/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/MavenImages.java @@ -54,6 +54,10 @@ public class MavenImages { public static final ImageDescriptor COLLAPSEALL = createDescriptor("collapseall.gif"); //$NON-NLS-1$ + public static final ImageDescriptor SUSPEND = createDescriptor("suspend.gif"); //$NON-NLS-1$ + + public static final ImageDescriptor CLEAR = createDescriptor("clear.gif"); //$NON-NLS-1$ + // object images public static final String PATH_JAR = "jar_obj.gif"; //$NON-NLS-1$ diff --git a/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/Messages.java b/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/Messages.java index aded9ac4..7f72ea38 100644 --- a/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/Messages.java +++ b/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/Messages.java @@ -863,6 +863,24 @@ public class Messages extends NLS { public static String LifecycleMappingPreferencePage_this_message; + public static String BuildDebugView_columnName; + + public static String BuildDebugView_columnBuildNumber; + + public static String BuildDebugView_nodeExecutions; + + public static String BuildDebugView_nodeDelta; + + public static String BuildDebugView_actionSuspend; + + public static String BuildDebugView_actionClear; + + public static String BuildDebugView_actionCollapseAll; + + public static String BuildDebugView_errorTitle; + + public static String BuildDebugView_errorDescription; + static { // initialize resource bundle NLS.initializeMessages(BUNDLE_NAME, Messages.class); diff --git a/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/messages.properties b/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/messages.properties index b56d9fbb..c01d6abf 100644 --- a/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/messages.properties +++ b/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/messages.properties @@ -431,3 +431,15 @@ wizardProjectPageProjectTitle=New Maven project wizardProjectPageProjectValidatorInvalidLocation=Invalid project location path wizardProjectPageProjectValidatorProjectLocation=Enter a location for the project. wizardProjectTitle=New Maven Project +BuildDebugView_columnName=Name +BuildDebugView_columnBuildNumber=Build# +BuildDebugView_nodeExecutions=executions +BuildDebugView_nodeDelta=delta +BuildDebugView_actionSuspend=Suspend +BuildDebugView_actionClear=Clear +BuildDebugView_actionCollapseAll=Collapse All +BuildDebugView_errorTitle=Build debug error +BuildDebugView_errorDescription=Could not collection build log + + + diff --git a/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/views/build/BuildDebugView.java b/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/views/build/BuildDebugView.java new file mode 100644 index 00000000..81265573 --- /dev/null +++ b/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/views/build/BuildDebugView.java @@ -0,0 +1,325 @@ +/******************************************************************************* + * Copyright (c) 2013 Igor Fedorenko + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Igor Fedorenko - initial API and implementation + *******************************************************************************/ + +package org.eclipse.m2e.core.ui.internal.views.build; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IResourceDelta; +import org.eclipse.core.resources.IResourceDeltaVisitor; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.jface.dialogs.ErrorDialog; +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.graphics.Image; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Tree; +import org.eclipse.swt.widgets.TreeColumn; +import org.eclipse.ui.IActionBars; +import org.eclipse.ui.IViewSite; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.part.ViewPart; + +import org.eclipse.m2e.core.internal.builder.BuildDebugHook; +import org.eclipse.m2e.core.internal.builder.MavenBuilder; +import org.eclipse.m2e.core.project.IMavenProjectFacade; +import org.eclipse.m2e.core.project.configurator.AbstractBuildParticipant; +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") +public class BuildDebugView extends ViewPart implements BuildDebugHook { + + /*package*/static final Comparator<Node> NODE_COMPARATOR = new Comparator<Node>() { + public int compare(Node p1, Node p2) { + int d = p2.getBuildCount() - p1.getBuildCount(); + if(d != 0) { + return d; + } + return p1.getName().compareTo(p2.getName()); + } + }; + + /*package*/TreeViewer viewer; + + /*package*/final Object projectsLock = new Object() { + }; + + /*package*/final Map<String, ProjectNode> projects = new ConcurrentHashMap<String, ProjectNode>(); + + /*package*/final Job refreshJob = new Job("") { + protected IStatus run(IProgressMonitor monitor) { + getSite().getShell().getDisplay().asyncExec(new Runnable() { + public void run() { + viewer.refresh(); +// for(TreeColumn column : viewer.getTree().getColumns()) { +// column.pack(); +// } + } + }); + return Status.OK_STATUS; + } + }; + + /*package*/volatile boolean suspended = true; + + public void createPartControl(Composite parent) { + viewer = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL); + Tree tree = viewer.getTree(); + tree.setHeaderVisible(true); + tree.setLinesVisible(true); + + TreeViewerColumn treeViewerColumn = new TreeViewerColumn(viewer, SWT.NONE); + TreeColumn trclmnName = treeViewerColumn.getColumn(); + trclmnName.setWidth(400); + trclmnName.setText(Messages.BuildDebugView_columnName); + + TreeViewerColumn treeViewerColumn_1 = new TreeViewerColumn(viewer, SWT.NONE); + TreeColumn trclmnBuildCount = treeViewerColumn_1.getColumn(); + trclmnBuildCount.setWidth(100); + trclmnBuildCount.setText(Messages.BuildDebugView_columnBuildNumber); + viewer.setLabelProvider(new ITableLabelProvider() { + + public void removeListener(ILabelProviderListener listener) { + } + + public boolean isLabelProperty(Object element, String property) { + return false; + } + + public void dispose() { + } + + public void addListener(ILabelProviderListener listener) { + } + + public String getColumnText(Object element, int columnIndex) { + if(element instanceof Node) { + return getColumnText((Node) element, columnIndex); + } + + if(columnIndex == 0) { + return element.toString(); + } + + return null; + } + + private String getColumnText(Node element, int columnIndex) { + switch(columnIndex) { + case 0: + return element.getName(); + case 1: + return Integer.toString(element.getBuildCount()); + default: + // fall through + } + return null; + } + + public Image getColumnImage(Object element, int columnIndex) { + return null; + } + }); + + viewer.setContentProvider(new ITreeContentProvider() { + + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + } + + public void dispose() { + } + + public boolean hasChildren(Object element) { + if(element instanceof ContainerNode) { + return !((ContainerNode) element).getResources().isEmpty(); + } + if(element instanceof CollectionNode<?>) { + return !((CollectionNode<?>) element).getMembers().isEmpty(); + } + return false; + } + + public Object getParent(Object element) { + return null; + } + + public Object[] getElements(Object inputElement) { + if(inputElement == projects) { + List<ProjectNode> sorted; + synchronized(projectsLock) { + sorted = new ArrayList<ProjectNode>(projects.values()); + } + Collections.sort(sorted, NODE_COMPARATOR); + return sorted.toArray(); + } + return new Object[0]; + } + + public Object[] getChildren(Object parentElement) { + if(parentElement instanceof ProjectNode) { + ArrayList<Object> result = new ArrayList<Object>(); + + final ProjectNode projectNode = (ProjectNode) parentElement; + + final List<ResourceNode> resources = new ArrayList<ResourceNode>(projectNode.getResources()); + if(!resources.isEmpty()) { + Collections.sort(resources, NODE_COMPARATOR); + result.add(new CollectionNode<ResourceNode>(Messages.BuildDebugView_nodeDelta, resources)); + } + + final List<MojoExecutionNode> executions = new ArrayList<MojoExecutionNode>(projectNode.getMojoExecutions()); + if(!executions.isEmpty()) { + Collections.sort(executions, NODE_COMPARATOR); + result.add(new CollectionNode<MojoExecutionNode>(Messages.BuildDebugView_nodeExecutions, executions)); + } + + return result.toArray(); + } else if(parentElement instanceof CollectionNode<?>) { + return ((CollectionNode<?>) parentElement).getMembers().toArray(); + } else if(parentElement instanceof ContainerNode) { + return ((ContainerNode) parentElement).getResources().toArray(); + } + return null; + } + }); + + viewer.setInput(projects); + + IActionBars actionBars = getViewSite().getActionBars(); + IToolBarManager toolBar = actionBars.getToolBarManager(); + Action suspendAction = new Action(Messages.BuildDebugView_actionSuspend, IAction.AS_CHECK_BOX) { + public void run() { + suspended = isChecked(); + } + }; + suspendAction.setImageDescriptor(MavenImages.SUSPEND); + suspendAction.setChecked(suspended); + Action clearAction = new Action(Messages.BuildDebugView_actionClear, MavenImages.CLEAR) { + public void run() { + synchronized(projectsLock) { + projects.clear(); + } + refreshJob.schedule(); + } + }; + Action collapseAll = new Action(Messages.BuildDebugView_actionCollapseAll, MavenImages.COLLAPSEALL) { + public void run() { + viewer.collapseAll(); + } + }; + toolBar.add(collapseAll); + toolBar.add(clearAction); + toolBar.add(suspendAction); + actionBars.updateActionBars(); + } + + public void setFocus() { + } + + public void init(IViewSite site) throws PartInitException { + super.init(site); + MavenBuilder.addDebugHook(this); + } + + public void dispose() { + MavenBuilder.removeDebugHook(this); + super.dispose(); + } + + public void buildStart(IMavenProjectFacade projectFacade, int kind, Map<String, String> args, + Map<MojoExecutionKey, List<AbstractBuildParticipant>> participants, IResourceDelta delta, IProgressMonitor monitor) { + + if(suspended) { + return; + } + + final ProjectNode projectNode = getProjectNode(projectFacade); + + final int buildCount = projectNode.incrementBuildCount(); + + try { + if(delta != null) { + delta.accept(new IResourceDeltaVisitor() { + public boolean visit(IResourceDelta delta) { + if(delta.getAffectedChildren().length == 0) { + IResource resource = delta.getResource(); + if(resource instanceof IFile || resource instanceof IFolder) { + projectNode.addResource(resource.getProjectRelativePath()).setBuildCount(buildCount); + } + } + return true; // keep visiting + } + }); + } + refreshJob.schedule(1000L); + } catch(CoreException ex) { + ErrorDialog.openError(getSite().getShell(), Messages.BuildDebugView_errorTitle, + Messages.BuildDebugView_errorDescription, ex.getStatus()); + } + } + + private ProjectNode getProjectNode(IMavenProjectFacade projectFacade) { + synchronized(projectsLock) { + IProject project = projectFacade.getProject(); + ProjectNode projectNode = projects.get(project.getName()); + if(projectNode == null) { + projectNode = new ProjectNode(project.getName()); + projects.put(project.getName(), projectNode); + } + return projectNode; + } + } + + public void buildParticipant(IMavenProjectFacade projectFacade, MojoExecutionKey mojoExecutionKey, + AbstractBuildParticipant participant, Set<File> files, IProgressMonitor monitor) { + + if(suspended || files == null || files.isEmpty()) { + return; + } + + final ProjectNode projectNode = getProjectNode(projectFacade); + final int buildCount = projectNode.getBuildCount(); + + // TODO secondary participants + // ... although they are unlikely to use BuildContext so we don't know what resources they modify + final MojoExecutionNode executionNode = projectNode.getMojoExecutionNode(mojoExecutionKey); + executionNode.setBuildCount(buildCount); + for(File file : files) { + executionNode.addResource(projectFacade.getProjectRelativePath(file.getAbsolutePath())).setBuildCount(buildCount); + } + } +} diff --git a/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/views/build/CollectionNode.java b/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/views/build/CollectionNode.java new file mode 100644 index 00000000..1244ea81 --- /dev/null +++ b/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/views/build/CollectionNode.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2013 Igor Fedorenko + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Igor Fedorenko - initial API and implementation + *******************************************************************************/ + +package org.eclipse.m2e.core.ui.internal.views.build; + +import java.util.Collection; + + +class CollectionNode<T extends Node> implements Node { + + private final String name; + + private final Collection<T> members; + + public CollectionNode(String name, Collection<T> members) { + this.name = name; + this.members = members; + } + + public Collection<T> getMembers() { + return members; + } + + public String getName() { + return name; + } + + public int getBuildCount() { + int result = 0; + for(Node member : members) { + if(result < member.getBuildCount()) { + result = member.getBuildCount(); + } + } + return result; + } +} diff --git a/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/views/build/ContainerNode.java b/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/views/build/ContainerNode.java new file mode 100644 index 00000000..d84b0546 --- /dev/null +++ b/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/views/build/ContainerNode.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2013 Igor Fedorenko + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Igor Fedorenko - initial API and implementation + *******************************************************************************/ + +package org.eclipse.m2e.core.ui.internal.views.build; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.core.runtime.IPath; + + +abstract class ContainerNode implements Node { + private final String name; + + private final Map<IPath, ResourceNode> resources = new HashMap<IPath, ResourceNode>(); + + protected ContainerNode(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public synchronized ResourceNode addResource(IPath path) { + ResourceNode child = resources.get(path); + if(child == null) { + child = new ResourceNode(path); + resources.put(path, child); + } + return child; + } + + public synchronized Collection<ResourceNode> getResources() { + return new ArrayList<ResourceNode>(resources.values()); + } + +} diff --git a/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/views/build/MojoExecutionNode.java b/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/views/build/MojoExecutionNode.java new file mode 100644 index 00000000..64631667 --- /dev/null +++ b/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/views/build/MojoExecutionNode.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2013 Igor Fedorenko + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Igor Fedorenko - initial API and implementation + *******************************************************************************/ + +package org.eclipse.m2e.core.ui.internal.views.build; + +import org.eclipse.m2e.core.project.configurator.MojoExecutionKey; + + +class MojoExecutionNode extends ContainerNode { + + private final MojoExecutionKey mojoExecutionKey; + + private int buildCount; + + public MojoExecutionNode(MojoExecutionKey mojoExecutionKey) { + super(mojoExecutionKey.toString()); + this.mojoExecutionKey = mojoExecutionKey; + } + + public MojoExecutionKey getMojoExecutionKey() { + return mojoExecutionKey; + } + + public synchronized int getBuildCount() { + return buildCount; + } + + public void setBuildCount(int buildCount) { + this.buildCount = buildCount; + } +} diff --git a/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/views/build/Node.java b/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/views/build/Node.java new file mode 100644 index 00000000..5376433e --- /dev/null +++ b/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/views/build/Node.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * Copyright (c) 2013 Igor Fedorenko + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Igor Fedorenko - initial API and implementation + *******************************************************************************/ + +package org.eclipse.m2e.core.ui.internal.views.build; + +interface Node { + + public String getName(); + + public int getBuildCount(); +} diff --git a/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/views/build/ProjectNode.java b/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/views/build/ProjectNode.java new file mode 100644 index 00000000..a5806dbb --- /dev/null +++ b/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/views/build/ProjectNode.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright (c) 2013 Igor Fedorenko + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Igor Fedorenko - initial API and implementation + *******************************************************************************/ + +package org.eclipse.m2e.core.ui.internal.views.build; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; + +import org.eclipse.m2e.core.project.configurator.MojoExecutionKey; + + +class ProjectNode extends ContainerNode { + + private final Map<MojoExecutionKey, MojoExecutionNode> executions = new HashMap<MojoExecutionKey, MojoExecutionNode>(); + + private final AtomicInteger buildCount = new AtomicInteger(); + + public ProjectNode(String name) { + super(name); + } + + public int incrementBuildCount() { + return buildCount.incrementAndGet(); + } + + public int getBuildCount() { + return buildCount.get(); + } + + public synchronized MojoExecutionNode getMojoExecutionNode(MojoExecutionKey mojoExecutionKey) { + MojoExecutionNode node = executions.get(mojoExecutionKey); + if(node == null) { + node = new MojoExecutionNode(mojoExecutionKey); + executions.put(mojoExecutionKey, node); + } + return node; + } + + public synchronized Collection<MojoExecutionNode> getMojoExecutions() { + return new ArrayList<MojoExecutionNode>(executions.values()); + } +} diff --git a/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/views/build/ResourceNode.java b/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/views/build/ResourceNode.java new file mode 100644 index 00000000..21009f6f --- /dev/null +++ b/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/views/build/ResourceNode.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2013 Igor Fedorenko + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Igor Fedorenko - initial API and implementation + *******************************************************************************/ + +package org.eclipse.m2e.core.ui.internal.views.build; + +import org.eclipse.core.runtime.IPath; + + +class ResourceNode implements Node { + + private final IPath path; + + private int buildCount; + + public ResourceNode(IPath path) { + this.path = path; + } + + public String getName() { + return path.toPortableString(); + } + + public IPath getPath() { + return path; + } + + public synchronized int getBuildCount() { + return buildCount; + } + + public void setBuildCount(int buildCount) { + this.buildCount = buildCount; + } +} diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/builder/BuildDebugHook.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/builder/BuildDebugHook.java new file mode 100644 index 00000000..e81d2cf6 --- /dev/null +++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/builder/BuildDebugHook.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2013 Igor Fedorenko + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Igor Fedorenko - initial API and implementation + *******************************************************************************/ + +package org.eclipse.m2e.core.internal.builder; + +import java.io.File; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.eclipse.core.resources.IResourceDelta; +import org.eclipse.core.runtime.IProgressMonitor; + +import org.eclipse.m2e.core.project.IMavenProjectFacade; +import org.eclipse.m2e.core.project.configurator.AbstractBuildParticipant; +import org.eclipse.m2e.core.project.configurator.MojoExecutionKey; + + +/** + * @noreference This internal interface can be changed or removed without notice. + * @since 1.4 + */ +public interface BuildDebugHook { + + public void buildStart(IMavenProjectFacade projectFacade, int kind, Map<String, String> args, + Map<MojoExecutionKey, List<AbstractBuildParticipant>> participants, IResourceDelta delta, IProgressMonitor monitor); + + public void buildParticipant(IMavenProjectFacade projectFacade, MojoExecutionKey mojoExecutionKey, + AbstractBuildParticipant participant, Set<File> files, IProgressMonitor monitor); + +} diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/builder/MavenBuilder.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/builder/MavenBuilder.java index ae424ab9..616d2781 100644 --- a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/builder/MavenBuilder.java +++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/builder/MavenBuilder.java @@ -11,8 +11,11 @@ package org.eclipse.m2e.core.internal.builder; +import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.ListIterator; import java.util.Map; import java.util.Set; @@ -204,4 +207,35 @@ public class MavenBuilder extends IncrementalProjectBuilder implements DeltaProv return projectFacade; } + + private static final List<BuildDebugHook> debugHooks = new ArrayList<BuildDebugHook>(); + + public static void addDebugHook(BuildDebugHook hook) { + synchronized(debugHooks) { + for(BuildDebugHook other : debugHooks) { + if(other == hook) { + return; + } + } + debugHooks.add(hook); + } + } + + public static void removeDebugHook(BuildDebugHook hook) { + synchronized(debugHooks) { + ListIterator<BuildDebugHook> iter = debugHooks.listIterator(); + while(iter.hasNext()) { + if(iter.next() == hook) { + iter.remove(); + break; + } + } + } + } + + public static Collection<BuildDebugHook> getDebugHooks() { + synchronized(debugHooks) { + return new ArrayList<BuildDebugHook>(debugHooks); + } + } } diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/builder/MavenBuilderImpl.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/builder/MavenBuilderImpl.java index 49907418..91aeee8d 100644 --- a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/builder/MavenBuilderImpl.java +++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/builder/MavenBuilderImpl.java @@ -16,10 +16,12 @@ import static org.eclipse.core.resources.IncrementalProjectBuilder.FULL_BUILD; import static org.eclipse.core.resources.IncrementalProjectBuilder.INCREMENTAL_BUILD; import java.io.File; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -83,6 +85,8 @@ public class MavenBuilderImpl { public Set<IProject> build(MavenSession session, IMavenProjectFacade projectFacade, int kind, Map<String, String> args, Map<MojoExecutionKey, List<AbstractBuildParticipant>> participants, IProgressMonitor monitor) throws CoreException { + Collection<BuildDebugHook> debugHooks = MavenBuilder.getDebugHooks(); + Set<IProject> dependencies = new HashSet<IProject>(); MavenProject mavenProject = projectFacade.getMavenProject(); @@ -106,13 +110,17 @@ public class MavenBuilderImpl { } } + debugBuildStart(debugHooks, projectFacade, kind, args, participants, delta, monitor); + Map<Throwable, MojoExecutionKey> buildErrors = new LinkedHashMap<Throwable, MojoExecutionKey>(); ThreadBuildContext.setThreadBuildContext(buildContext); MavenProjectMutableState snapshot = MavenProjectMutableState.takeSnapshot(mavenProject); try { for(Entry<MojoExecutionKey, List<AbstractBuildParticipant>> entry : participants.entrySet()) { + MojoExecutionKey mojoExecutionKey = entry.getKey(); for(InternalBuildParticipant participant : entry.getValue()) { - MojoExecutionKey mojoExecutionKey = entry.getKey(); + Set<File> debugRefreshFiles = !debugHooks.isEmpty() ? new LinkedHashSet<File>(buildContext.getFiles()) : null; + log.debug("Executing build participant {} for plugin execution {}", participant.getClass().getName(), mojoExecutionKey.toString()); String stringMojoExecutionKey = mojoExecutionKey.getKeyString(); @@ -149,6 +157,9 @@ public class MavenBuilderImpl { processMavenSessionErrors(session, mojoExecutionKey, buildErrors); } + + debugBuildParticipant(debugHooks, projectFacade, mojoExecutionKey, (AbstractBuildParticipant) participant, + diff(debugRefreshFiles, buildContext.getFiles()), monitor); } } } catch(Exception e) { @@ -164,9 +175,42 @@ public class MavenBuilderImpl { // Process errors and warnings MavenExecutionResult result = session.getResult(); processBuildResults(project, mavenProject, result, buildContext, buildErrors); + + debugBuildEnd(debugHooks, projectFacade, buildContext, monitor); + return dependencies; } + private void debugBuildParticipant(Collection<BuildDebugHook> hooks, IMavenProjectFacade projectFacade, + MojoExecutionKey mojoExecutionKey, AbstractBuildParticipant participant, Set<File> files, IProgressMonitor monitor) { + for(BuildDebugHook hook : hooks) { + hook.buildParticipant(projectFacade, mojoExecutionKey, participant, files, monitor); + } + } + + private Set<File> diff(Set<File> before, Set<File> after) { + if(before == null) { + return after; + } + Set<File> result = new LinkedHashSet<File>(after); + result.removeAll(before); + return result; + } + + private void debugBuildStart(Collection<BuildDebugHook> hooks, IMavenProjectFacade projectFacade, int kind, + Map<String, String> args, Map<MojoExecutionKey, List<AbstractBuildParticipant>> participants, + IResourceDelta delta, IProgressMonitor monitor) { + for(BuildDebugHook hook : hooks) { + hook.buildStart(projectFacade, kind, args, participants, delta, monitor); + } + } + + private void debugBuildEnd(Collection<BuildDebugHook> hooks, IMavenProjectFacade projectFacade, + AbstractEclipseBuildContext buildContext, IProgressMonitor monitor) { + for(BuildDebugHook hook : hooks) { + } + } + protected boolean isApplicable(InternalBuildParticipant participant, int kind, IResourceDelta delta) { return FULL_BUILD == kind || delta != null || participant.callOnEmptyDelta(); } |