blob: 948043ce17bd3e29ed0c16c81fa795c7b125dda2 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2004 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.ui.externaltools.internal.model;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import org.eclipse.core.resources.IFile;
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.resources.IncrementalProjectBuilder;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchManager;
import org.eclipse.ui.externaltools.internal.launchConfigurations.ExternalToolsUtil;
import org.eclipse.ui.externaltools.internal.registry.ExternalToolMigration;
import org.osgi.framework.Bundle;
/**
* This project builder implementation will run an external tool during the
* build process.
*/
public final class ExternalToolBuilder extends IncrementalProjectBuilder {
private final class IgnoreTeamPrivateChanges implements IResourceDeltaVisitor {
private boolean[] fTrueChange;
private IgnoreTeamPrivateChanges(boolean[] trueChange) {
super();
fTrueChange= trueChange;
}
public boolean visit(IResourceDelta visitDelta) throws CoreException {
IResource resource= visitDelta.getResource();
if (resource instanceof IFile) {
fTrueChange[0]= true;
return false;
}
return true;
}
}
public static final String ID = "org.eclipse.ui.externaltools.ExternalToolBuilder"; //$NON-NLS-1$;
private static final String BUILD_TYPE_SEPARATOR = ","; //$NON-NLS-1$
private static final int[] DEFAULT_BUILD_TYPES= new int[] {
IncrementalProjectBuilder.INCREMENTAL_BUILD,
IncrementalProjectBuilder.FULL_BUILD};
private static String buildType = IExternalToolConstants.BUILD_TYPE_NONE;
private static IProject buildProject= null;
private List projectsWithinScope;
private boolean buildKindCompatible(int kind, ILaunchConfiguration config) throws CoreException {
int[] buildKinds = buildTypesToArray(config.getAttribute(IExternalToolConstants.ATTR_RUN_BUILD_KINDS, "")); //$NON-NLS-1$
for (int j = 0; j < buildKinds.length; j++) {
if (kind == buildKinds[j]) {
return true;
}
}
return false;
}
/* (non-Javadoc)
* @see org.eclipse.core.internal.events.InternalBuilder#build(int, java.util.Map, org.eclipse.core.runtime.IProgressMonitor)
*/
protected IProject[] build(int kind, Map args, IProgressMonitor monitor) throws CoreException {
if (ExternalToolsPlugin.getDefault().getBundle().getState() != Bundle.ACTIVE) {
return null;
}
projectsWithinScope= new ArrayList();
ILaunchConfiguration config = BuilderUtils.configFromBuildCommandArgs(getProject(), args, new String[1]);
if (config != null && buildKindCompatible(kind, config) && configEnabled(config)) {
doBuildBasedOnScope(kind, config, monitor);
}
return getProjectsWithinScope();
}
/**
* Returns whether the given builder config is enabled or not.
*
* @param config the config to examine
* @return whether the config is enabled
*/
private boolean configEnabled(ILaunchConfiguration config) {
try {
return ExternalToolsUtil.isBuilderEnabled(config);
} catch (CoreException e) {
ExternalToolsPlugin.getDefault().log(e);
}
return true;
}
private IProject[] getProjectsWithinScope() {
if (projectsWithinScope == null || projectsWithinScope.isEmpty()) {
projectsWithinScope = null;
return null;
}
return (IProject[])projectsWithinScope.toArray(new IProject[projectsWithinScope.size()]);
}
private void doBuildBasedOnScope(int kind, ILaunchConfiguration config, IProgressMonitor monitor) throws CoreException {
boolean buildForChange = true;
if (kind != FULL_BUILD) { //scope not applied for full builds
IResource[] resources = ExternalToolsUtil.getResourcesForBuildScope(config);
if (resources != null && resources.length > 0) {
for (int i = 0; i < resources.length; i++) {
IResource resource = resources[i];
projectsWithinScope.add(resource.getProject());
}
buildForChange = buildScopeIndicatesBuild(resources);
}
}
if (buildForChange) {
launchBuild(kind, config, monitor);
}
}
private void launchBuild(int kind, ILaunchConfiguration config, IProgressMonitor monitor) throws CoreException {
monitor.subTask(MessageFormat.format(ExternalToolsModelMessages.getString("ExternalToolBuilder.Running_{0}..._1"), new String[] { config.getName()})); //$NON-NLS-1$
buildStarted(kind);
// The default value for "launch in background" is true in debug core. If
// the user doesn't go through the UI, the new attribute won't be set. This means
// that existing Ant builders will try to run in the background (and likely conflict with
// each other) without migration.
config= ExternalToolMigration.migrateRunInBackground(config);
config.launch(ILaunchManager.RUN_MODE, monitor);
buildEnded();
}
/**
* Returns the build type being performed if the
* external tool is being run as a project builder.
*
* @return one of the <code>IExternalToolConstants.BUILD_TYPE_*</code> constants.
*/
public static String getBuildType() {
return buildType;
}
/**
* Returns the project that is being built and has triggered the current external
* tool builder. <code>null</code> is returned if no build is currently occurring.
*
* @return project being built or <code>null</code>.
*/
public static IProject getBuildProject() {
return buildProject;
}
/**
* Stores the currently active build kind and build project when a build begins
* @param buildKind
*/
private void buildStarted(int buildKind) {
switch (buildKind) {
case IncrementalProjectBuilder.INCREMENTAL_BUILD :
buildType = IExternalToolConstants.BUILD_TYPE_INCREMENTAL;
break;
case IncrementalProjectBuilder.FULL_BUILD :
buildType = IExternalToolConstants.BUILD_TYPE_FULL;
break;
case IncrementalProjectBuilder.AUTO_BUILD :
buildType = IExternalToolConstants.BUILD_TYPE_AUTO;
break;
default :
buildType = IExternalToolConstants.BUILD_TYPE_NONE;
break;
}
buildProject= getProject();
}
/**
* Clears the current build kind and build project when a build finishes.
*/
private void buildEnded() {
buildType= IExternalToolConstants.BUILD_TYPE_NONE;
buildProject= null;
}
private boolean buildScopeIndicatesBuild(IResource[] resources) {
for (int i = 0; i < resources.length; i++) {
IResourceDelta delta = getDelta(resources[i].getProject());
if (delta == null) {
//project just added to the workspace..no previous build tree
return true;
}
IPath path= resources[i].getProjectRelativePath();
IResourceDelta change= delta.findMember(path);
if (change != null) {
final boolean[] trueChange= new boolean[1];
trueChange[0]= false;
try {
change.accept(new IgnoreTeamPrivateChanges(trueChange));
} catch (CoreException e) {
ExternalToolsPlugin.getDefault().log("Internal error resolving changed resources during build", e); //$NON-NLS-1$
}
return trueChange[0]; //filtered out team private changes
}
}
return false;
}
/**
* Converts the build types string into an array of
* build kinds.
*
* @param buildTypes the string of built types to convert
* @return the array of build kinds.
*/
public static int[] buildTypesToArray(String buildTypes) {
if (buildTypes == null || buildTypes.length() == 0) {
return DEFAULT_BUILD_TYPES;
}
int count = 0;
boolean incremental = false;
boolean full = false;
boolean auto = false;
StringTokenizer tokenizer = new StringTokenizer(buildTypes, BUILD_TYPE_SEPARATOR);
while (tokenizer.hasMoreTokens()) {
String token = tokenizer.nextToken();
if (IExternalToolConstants.BUILD_TYPE_INCREMENTAL.equals(token)) {
if (!incremental) {
incremental = true;
count++;
}
} else if (IExternalToolConstants.BUILD_TYPE_FULL.equals(token)) {
if (!full) {
full = true;
count++;
}
} else if (IExternalToolConstants.BUILD_TYPE_AUTO.equals(token)) {
if (!auto) {
auto = true;
count++;
}
}
}
int[] results = new int[count];
count = 0;
if (incremental) {
results[count] = IncrementalProjectBuilder.INCREMENTAL_BUILD;
count++;
}
if (full) {
results[count] = IncrementalProjectBuilder.FULL_BUILD;
count++;
}
if (auto) {
results[count] = IncrementalProjectBuilder.AUTO_BUILD;
count++;
}
return results;
}
}