blob: c9b10d84ac93c81f7c3094d004fe74c3aac1d2b5 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008-2010 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
*******************************************************************************/
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;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.apache.maven.project.MavenProject;
import org.eclipse.m2e.core.MavenPlugin;
import org.eclipse.m2e.core.embedder.IMavenExecutionContext;
import org.eclipse.m2e.core.internal.IMavenConstants;
import org.eclipse.m2e.core.internal.M2EUtils;
import org.eclipse.m2e.core.internal.MavenPluginActivator;
import org.eclipse.m2e.core.internal.embedder.MavenExecutionContext;
import org.eclipse.m2e.core.internal.markers.IMavenMarkerManager;
import org.eclipse.m2e.core.internal.project.registry.ProjectRegistryManager;
import org.eclipse.m2e.core.project.IMavenProjectFacade;
import org.eclipse.m2e.core.project.IProjectConfigurationManager;
import org.eclipse.m2e.core.project.ResolverConfiguration;
import org.eclipse.m2e.core.project.configurator.AbstractBuildParticipant;
import org.eclipse.m2e.core.project.configurator.ILifecycleMapping;
import org.eclipse.m2e.core.project.configurator.MojoExecutionKey;
public class MavenBuilder extends IncrementalProjectBuilder implements DeltaProvider {
static final Logger log = LoggerFactory.getLogger(MavenBuilder.class);
final MavenBuilderImpl builder = new MavenBuilderImpl(this);
private abstract class BuildMethod<T> {
final ProjectRegistryManager projectManager = MavenPluginActivator.getDefault().getMavenProjectManagerImpl();
final IProjectConfigurationManager configurationManager = MavenPlugin.getProjectConfigurationManager();
final IMavenMarkerManager markerManager = MavenPluginActivator.getDefault().getMavenMarkerManager();
public BuildMethod() {
}
public final T execute(final int kind, final Map<String, String> args, IProgressMonitor monitor)
throws CoreException {
final IProject project = getProject();
markerManager.deleteMarkers(project, kind == FULL_BUILD || kind == CLEAN_BUILD, IMavenConstants.MARKER_BUILD_ID);
final IFile pomResource = project.getFile(IMavenConstants.POM_FILE_NAME);
if(pomResource == null) {
return null;
}
ResolverConfiguration resolverConfiguration = configurationManager.getResolverConfiguration(project);
if(resolverConfiguration == null) {
// TODO unit test me
return null;
}
final MavenExecutionContext context = projectManager.createExecutionContext(pomResource, resolverConfiguration);
return context.execute((context2, monitor2) -> {
final IMavenProjectFacade projectFacade = getProjectFacade(project, monitor2);
if(projectFacade == null) {
return null;
}
MavenProject mavenProject;
try {
// make sure projectFacade has MavenProject instance loaded
mavenProject = projectFacade.getMavenProject(monitor2);
} catch(CoreException ce) {
//unable to read the project facade
addErrorMarker(project, ce);
return null;
}
return context2.execute(mavenProject, (context1, monitor1) -> {
ILifecycleMapping lifecycleMapping = configurationManager.getLifecycleMapping(projectFacade);
if(lifecycleMapping == null) {
return null;
}
Map<MojoExecutionKey, List<AbstractBuildParticipant>> buildParticipantsByMojoExecutionKey = lifecycleMapping
.getBuildParticipants(projectFacade, monitor1);
return method(context1, projectFacade, buildParticipantsByMojoExecutionKey, kind, args, monitor1);
}, monitor2);
}, monitor);
}
abstract T method(IMavenExecutionContext context, IMavenProjectFacade projectFacade,
Map<MojoExecutionKey, List<AbstractBuildParticipant>> buildParticipantsByMojoExecutionKey, int kind,
Map<String, String> args, IProgressMonitor monitor) throws CoreException;
void addErrorMarker(IProject project, Exception e) {
String msg = e.getMessage();
String rootCause = M2EUtils.getRootCauseMessage(e);
if(msg != null && !msg.equals(rootCause)) {
msg = msg + ": " + rootCause; //$NON-NLS-1$
}
markerManager.addMarker(project, IMavenConstants.MARKER_BUILD_ID, msg, 1, IMarker.SEVERITY_ERROR);
}
IMavenProjectFacade getProjectFacade(final IProject project, final IProgressMonitor monitor) throws CoreException {
final IFile pomResource = project.getFile(IMavenConstants.POM_FILE_NAME);
// facade refresh should be forced whenever pom.xml has changed
// there is no delta info for full builds
// but these are usually forced from Project/Clean
// so assume pom did not change
boolean force = false;
IResourceDelta delta = getDelta(project);
if(delta != null) {
delta = delta.findMember(pomResource.getFullPath());
force = delta != null && delta.getKind() == IResourceDelta.CHANGED;
}
IMavenProjectFacade projectFacade = projectManager.getProject(project);
if(force || projectFacade == null || projectFacade.isStale()) {
projectManager.refresh(Collections.singleton(pomResource), monitor);
projectFacade = projectManager.getProject(project);
if(projectFacade == null) {
// error marker should have been created
return null;
}
}
return projectFacade;
}
}
private BuildMethod<IProject[]> methodBuild = new BuildMethod<IProject[]>() {
@Override
protected IProject[] method(IMavenExecutionContext context, IMavenProjectFacade projectFacade,
Map<MojoExecutionKey, List<AbstractBuildParticipant>> buildParticipantsByMojoExecutionKey, int kind,
Map<String, String> args, IProgressMonitor monitor) throws CoreException {
Set<IProject> dependencies = builder.build(context.getSession(), projectFacade, kind, args,
buildParticipantsByMojoExecutionKey, monitor);
if(dependencies.isEmpty()) {
return null;
}
return dependencies.toArray(new IProject[dependencies.size()]);
}
};
private BuildMethod<Void> methodClean = new BuildMethod<Void>() {
@Override
protected Void method(IMavenExecutionContext context, IMavenProjectFacade projectFacade,
Map<MojoExecutionKey, List<AbstractBuildParticipant>> buildParticipantsByMojoExecutionKey, int kind,
Map<String, String> args, IProgressMonitor monitor) throws CoreException {
builder.clean(context.getSession(), projectFacade, buildParticipantsByMojoExecutionKey, monitor);
return null;
}
};
protected IProject[] build(final int kind, final Map<String, String> args, final IProgressMonitor monitor)
throws CoreException {
log.debug("Building project {}", getProject().getName()); //$NON-NLS-1$
final long start = System.currentTimeMillis();
try {
return methodBuild.execute(kind, args, monitor);
} finally {
log.debug("Built project {} in {} ms", getProject().getName(), System.currentTimeMillis() - start); //$NON-NLS-1$
}
}
protected void clean(final IProgressMonitor monitor) throws CoreException {
log.debug("Cleaning project {}", getProject().getName()); //$NON-NLS-1$
final long start = System.currentTimeMillis();
try {
methodClean.execute(CLEAN_BUILD, Collections.<String, String> emptyMap(), monitor);
} finally {
log.debug("Cleaned project {} in {} ms", getProject().getName(), System.currentTimeMillis() - start); //$NON-NLS-1$
}
}
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);
}
}
public ISchedulingRule getRule(int kind, Map<String, String> args) {
if(MavenPlugin.getMavenConfiguration().buildWithNullSchedulingRule()) {
return null;
}
return super.getRule(kind, args);
}
}