blob: 17effc5e7bf26d8d876f92b96bcc484f4cd2add0 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2007 IBM Corporation and others.
* 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
*
*******************************************************************************/
package org.eclipse.dltk.internal.core.builder;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.resources.IMarker;
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.IResourceVisitor;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.dltk.core.DLTKContentTypeManager;
import org.eclipse.dltk.core.DLTKCore;
import org.eclipse.dltk.core.DLTKLanguageManager;
import org.eclipse.dltk.core.IBuildpathEntry;
import org.eclipse.dltk.core.IDLTKLanguageToolkit;
import org.eclipse.dltk.core.IModelElement;
import org.eclipse.dltk.core.IModelElementVisitor;
import org.eclipse.dltk.core.IModelMarker;
import org.eclipse.dltk.core.IProjectFragment;
import org.eclipse.dltk.core.IScriptFolder;
import org.eclipse.dltk.core.ModelException;
import org.eclipse.dltk.core.ScriptProjectUtil;
import org.eclipse.dltk.core.builder.IScriptBuilder;
import org.eclipse.dltk.core.builder.IScriptBuilderExtension;
import org.eclipse.dltk.core.environment.EnvironmentPathUtils;
import org.eclipse.dltk.internal.core.BuildpathEntry;
import org.eclipse.dltk.internal.core.BuiltinSourceModule;
import org.eclipse.dltk.internal.core.ExternalSourceModule;
import org.eclipse.dltk.internal.core.ModelManager;
import org.eclipse.dltk.internal.core.ScriptProject;
import org.eclipse.osgi.util.NLS;
public class ScriptBuilder extends IncrementalProjectBuilder {
public static final boolean DEBUG = DLTKCore.DEBUG_SCRIPT_BUILDER;
public static final boolean TRACE = DLTKCore.TRACE_SCRIPT_BUILDER;
public IProject currentProject = null;
ScriptProject scriptProject = null;
State lastState;
/**
* Last build following resource count.
*/
public long lastBuildResources = 0;
public long lastBuildSourceFiles = 0;
static class ResourceVisitor implements IResourceDeltaVisitor,
IResourceVisitor {
final Set resources = new HashSet();
private final IProgressMonitor monitor;
public ResourceVisitor(IProgressMonitor monitor) {
this.monitor = monitor;
}
public boolean visit(IResourceDelta delta) throws CoreException {
if (monitor.isCanceled()) {
return false;
}
IResource resource = delta.getResource();
if (resource.getType() == IResource.FOLDER) {
this.monitor
.subTask(Messages.ScriptBuilder_scanningProjectFolder
+ resource.getProjectRelativePath().toString());
}
if (resource.getType() == IResource.FILE) {
switch (delta.getKind()) {
case IResourceDelta.ADDED:
case IResourceDelta.CHANGED:
resources.add(resource);
break;
}
return false;
}
return true;
}
public boolean visit(IResource resource) {
if (monitor.isCanceled()) {
return false;
}
if (resource.getType() == IResource.FOLDER) {
this.monitor
.subTask(Messages.ScriptBuilder_scanningProjectFolder
+ resource.getProjectRelativePath().toString());
}
if (resource.getType() == IResource.FILE) {
resources.add(resource);
return false;
}
return true;
}
}
static class ExternalModuleVisitor implements IModelElementVisitor {
final Set elements = new HashSet();
private final IProgressMonitor monitor;
public ExternalModuleVisitor(IProgressMonitor monitor) {
this.monitor = monitor;
}
/**
* Visit only external source modules, witch we aren't builded yet.
*/
public boolean visit(IModelElement element) {
// monitor.worked(1);
if (monitor.isCanceled()) {
return false;
}
if (element.getElementType() == IModelElement.PROJECT_FRAGMENT) {
if (!(element instanceof IProjectFragment && ((IProjectFragment) element)
.isExternal())) {
return false;
}
IProjectFragment fragment = (IProjectFragment) element;
String localPath = EnvironmentPathUtils.getLocalPath(
fragment.getPath()).toString();
if (!localPath.startsWith("#")) { //$NON-NLS-1$
this.monitor
.subTask(Messages.ScriptBuilder_scanningExternalFolder
+ localPath);
}
} else if (element.getElementType() == IModelElement.SOURCE_MODULE) {
if (element instanceof ExternalSourceModule
|| element instanceof BuiltinSourceModule) {
elements.add(element);
}
return false; // do not enter into source module content.
} else if (element.getElementType() == IModelElement.SCRIPT_FOLDER) {
IScriptFolder folder = (IScriptFolder) element;
String localPath = EnvironmentPathUtils.getLocalPath(
folder.getPath()).toString();
if (!localPath.startsWith("#")) { //$NON-NLS-1$
this.monitor
.subTask(Messages.ScriptBuilder_scanningExternalFolder
+ localPath);
}
}
return true;
}
}
/**
* Hook allowing to initialize some static state before a complete build
* iteration. This hook is invoked during PRE_AUTO_BUILD notification
*/
public static void buildStarting() {
// build is about to start
}
/**
* Hook allowing to reset some static state after a complete build
* iteration. This hook is invoked during POST_AUTO_BUILD notification
*/
public static void buildFinished() {
if (TRACE)
System.out.println("build finished"); //$NON-NLS-1$
}
private static void log(String message) {
System.out.println(message);
}
private static final QualifiedName PROPERTY_BUILDER_VERSION = new QualifiedName(
DLTKCore.PLUGIN_ID, "builderVersion"); //$NON-NLS-1$
private static final String CURRENT_VERSION = "200810012003-2123"; //$NON-NLS-1$
protected IProject[] build(int kind, Map args, IProgressMonitor monitor)
throws CoreException {
this.currentProject = getProject();
if (currentProject == null || !currentProject.isAccessible())
return new IProject[0];
if (!DLTKLanguageManager.hasScriptNature(this.currentProject)) {
return null;
}
long startTime = 0;
if (DEBUG || TRACE) {
startTime = System.currentTimeMillis();
log("\nStarting build of " + this.currentProject.getName() //$NON-NLS-1$
+ " @ " + new Date(startTime)); //$NON-NLS-1$
}
this.scriptProject = (ScriptProject) DLTKCore.create(currentProject);
if (!ScriptProjectUtil.isBuilderEnabled(scriptProject)) {
return null;
}
final String version = currentProject
.getPersistentProperty(PROPERTY_BUILDER_VERSION);
if (version == null) {
removeWrongTaskMarkers();
currentProject.setPersistentProperty(PROPERTY_BUILDER_VERSION,
CURRENT_VERSION);
kind = FULL_BUILD;
} else if (!CURRENT_VERSION.equals(version)) {
if ("200810012003".equals(version)) { //$NON-NLS-1$
removeWrongTaskMarkers();
}
currentProject.setPersistentProperty(PROPERTY_BUILDER_VERSION,
CURRENT_VERSION);
kind = FULL_BUILD;
}
lastBuildResources = 0;
lastBuildSourceFiles = 0;
if (monitor == null) {
monitor = new NullProgressMonitor();
}
if (kind == FULL_BUILD) {
if (DEBUG)
log("Performing full build as requested by user"); //$NON-NLS-1$
fullBuild(monitor);
} else {
if ((this.lastState = getLastState(currentProject, monitor)) == null) {
if (DEBUG)
log("Performing full build since last saved state was not found"); //$NON-NLS-1$
fullBuild(monitor);
} else {
IResourceDelta delta = getDelta(getProject());
if (delta == null) {
if (DEBUG)
log("Performing full build since deltas are missing after incremental request"); //$NON-NLS-1$
fullBuild(monitor);
} else {
if (DEBUG)
log("Performing incremental build"); //$NON-NLS-1$
incrementalBuild(delta, monitor);
}
}
}
IProject[] requiredProjects = getRequiredProjects(true);
long endTime = 0;
if (DEBUG || TRACE) {
endTime = System.currentTimeMillis();
}
if (DEBUG) {
log("Finished build of " + currentProject.getName() //$NON-NLS-1$
+ " @ " + new Date(endTime) + ", elapsed " + (endTime - startTime) + " ms"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
if (TRACE) {
System.out
.println("-----SCRIPT-BUILDER-INFORMATION-TRACE----------------------------"); //$NON-NLS-1$
System.out.println("Finished build of project:" //$NON-NLS-1$
+ currentProject.getName() + "\n" //$NON-NLS-1$
+ "Building time:" //$NON-NLS-1$
+ Long.toString(endTime - startTime) + "\n" //$NON-NLS-1$
+ "Resources count:" //$NON-NLS-1$
+ this.lastBuildResources + "\n" //$NON-NLS-1$
+ "Sources count:" //$NON-NLS-1$
+ this.lastBuildSourceFiles + "\n" //$NON-NLS-1$
+ "Build type:" //$NON-NLS-1$
+ (kind == FULL_BUILD ? "Full build" //$NON-NLS-1$
: "Incremental build")); //$NON-NLS-1$
System.out
.println("-----------------------------------------------------------------"); //$NON-NLS-1$
}
monitor.done();
return requiredProjects;
}
/**
* Remove incorrect task markers.
*
* DLTK 0.95 were creating wrong task markers, so this function is here to
* remove them. New markers will be created by the builder later.
*
* @param project
* @throws CoreException
*/
private void removeWrongTaskMarkers() throws CoreException {
final IMarker[] markers = currentProject.findMarkers(IMarker.TASK,
false, IResource.DEPTH_INFINITE);
for (int i = 0; i < markers.length; ++i) {
final IMarker marker = markers[i];
final IResource resource = marker.getResource();
if (resource.getType() != IResource.FILE) {
continue;
}
if (!DLTKContentTypeManager.isValidResourceForContentType(
scriptProject.getLanguageToolkit(), resource)) {
continue;
}
final Map attributes = marker.getAttributes();
if (attributes == null) {
continue;
}
if (!Boolean.FALSE.equals(attributes.get(IMarker.USER_EDITABLE))) {
continue;
}
if (attributes.containsKey(IMarker.LINE_NUMBER)
&& attributes.containsKey(IMarker.MESSAGE)
&& attributes.containsKey(IMarker.PRIORITY)
&& attributes.containsKey(IMarker.CHAR_START)
&& attributes.containsKey(IMarker.CHAR_END)) {
marker.delete();
}
}
}
protected void clean(IProgressMonitor monitor) throws CoreException {
long start = 0;
if (TRACE) {
start = System.currentTimeMillis();
}
this.currentProject = getProject();
if (!DLTKLanguageManager.hasScriptNature(this.currentProject)) {
return;
}
this.scriptProject = (ScriptProject) DLTKCore.create(currentProject);
if (currentProject == null || !currentProject.isAccessible())
return;
try {
monitor.beginTask(NLS.bind(
Messages.ScriptBuilder_cleaningScriptsIn, currentProject
.getName()), 66);
if (monitor.isCanceled()) {
return;
}
IScriptBuilder[] builders = getScriptBuilders();
if (builders != null) {
for (int k = 0; k < builders.length; k++) {
IProgressMonitor sub = new SubProgressMonitor(monitor, 1);
builders[k].clean(scriptProject, sub);
if (monitor.isCanceled()) {
break;
}
}
}
resetBuilders(builders);
} catch (CoreException e) {
if (DLTKCore.DEBUG) {
e.printStackTrace();
}
}
if (TRACE) {
System.out
.println("-----SCRIPT-BUILDER-INFORMATION-TRACE----------------------------"); //$NON-NLS-1$
System.out.println("Finished clean of project:" //$NON-NLS-1$
+ currentProject.getName() + "\n" //$NON-NLS-1$
+ "Building time:" //$NON-NLS-1$
+ Long.toString(System.currentTimeMillis() - start));
System.out
.println("-----------------------------------------------------------------"); //$NON-NLS-1$
}
monitor.done();
}
private IProject[] getRequiredProjects(boolean includeBinaryPrerequisites) {
if (scriptProject == null)
return new IProject[0];
IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
ArrayList projects = new ArrayList();
try {
IBuildpathEntry[] entries = scriptProject
.getExpandedBuildpath(true);
for (int i = 0, l = entries.length; i < l; i++) {
IBuildpathEntry entry = entries[i];
IPath path = entry.getPath();
IProject p = null;
switch (entry.getEntryKind()) {
case IBuildpathEntry.BPE_PROJECT:
p = workspaceRoot.getProject(path.lastSegment());
// missing projects are considered too
if (((BuildpathEntry) entry).isOptional()
&& !ScriptProject.hasScriptNature(p))
// except if entry is optional
p = null;
break;
case IBuildpathEntry.BPE_LIBRARY:
if (includeBinaryPrerequisites && path.segmentCount() > 1) {
/*
* some binary resources on the class path can come from
* projects that are not included in the project
* references
*/
IResource resource = workspaceRoot.findMember(path
.segment(0));
if (resource instanceof IProject)
p = (IProject) resource;
}
}
if (p != null && !projects.contains(p))
projects.add(p);
}
} catch (ModelException e) {
return new IProject[0];
}
IProject[] result = new IProject[projects.size()];
projects.toArray(result);
return result;
}
public State getLastState(IProject project, IProgressMonitor monitor) {
return (State) ModelManager.getModelManager().getLastBuiltState(
project, monitor);
}
private State clearLastState() {
State state = new State(this);
State prevState = (State) ModelManager.getModelManager()
.getLastBuiltState(currentProject, null);
if (prevState != null) {
if (prevState.noCleanExternalFolders) {
state.externalFolderLocations = prevState.externalFolderLocations;
return state;
}
}
ModelManager.getModelManager().setLastBuiltState(currentProject, null);
return state;
}
private static final int WORK_RESOURCES = 50;
private static final int WORK_EXTERNAL = 100;
private static final int WORK_SOURCES = 100;
private static final int WORK_BUILD = 750;
private static final String NONAME = ""; //$NON-NLS-1$
protected void fullBuild(final IProgressMonitor monitor) {
State newState = clearLastState();
this.lastState = newState;
IScriptBuilder[] builders = null;
try {
monitor.setTaskName(NLS.bind(
Messages.ScriptBuilder_buildingScriptsIn, currentProject
.getName()));
monitor.beginTask(NONAME, WORK_RESOURCES + WORK_EXTERNAL
+ WORK_SOURCES + WORK_BUILD);
Set resources = getResourcesFrom(currentProject, monitor,
WORK_RESOURCES);
if (monitor.isCanceled()) {
return;
}
Set externalElements = getExternalElementsFrom(scriptProject,
monitor, WORK_EXTERNAL, true);
Set externalFolders = new HashSet(
this.lastState.externalFolderLocations);
if (monitor.isCanceled()) {
return;
}
// Project external resources should also be added into list. Only
// on full build we need to manage this.
// Call builders for resources.
int totalFiles = resources.size() + externalElements.size();
if (totalFiles == 0)
totalFiles = 1;
builders = getScriptBuilders();
List localResources = new ArrayList();
List localElements = new ArrayList();
locateSourceModules(monitor, WORK_SOURCES, resources,
localElements, localResources);
if (monitor.isCanceled()) {
return;
}
int resourceTicks = WORK_BUILD
* (resources.size() - localElements.size()) / totalFiles;
resourceTicks = Math.min(resourceTicks, WORK_BUILD / 4);
try {
buildElements(localElements, externalElements, monitor,
WORK_BUILD - resourceTicks, IScriptBuilder.FULL_BUILD,
Collections.EMPTY_SET, externalFolders, builders);
lastBuildSourceFiles += externalElements.size();
} catch (CoreException e) {
DLTKCore.error(Messages.ScriptBuilder_errorBuildElements, e);
}
if (monitor.isCanceled()) {
return;
}
buildResources(localResources, monitor, resourceTicks, FULL_BUILD,
builders);
lastBuildResources = resources.size() + externalElements.size();
} catch (CoreException e) {
if (DLTKCore.DEBUG) {
e.printStackTrace();
}
} finally {
resetBuilders(builders);
monitor.done();
ModelManager.getModelManager().setLastBuiltState(currentProject,
this.lastState);
}
}
private void resetBuilders(IScriptBuilder[] builders) {
if (builders != null) {
for (int k = 0; k < builders.length; k++) {
builders[k].reset(scriptProject);
}
}
}
private Set getResourcesFrom(Object el, final IProgressMonitor monitor,
int ticks) throws CoreException {
monitor.subTask(Messages.ScriptBuilder_scanningProject);
try {
ResourceVisitor resourceVisitor = new ResourceVisitor(monitor);
if (el instanceof IProject) {
IProject prj = (IProject) el;
prj.accept(resourceVisitor);
} else if (el instanceof IResourceDelta) {
IResourceDelta delta = (IResourceDelta) el;
delta.accept(resourceVisitor);
}
return resourceVisitor.resources;
} finally {
monitor.worked(ticks);
}
}
private Set getExternalElementsFrom(ScriptProject prj,
final IProgressMonitor monitor, int tiks, boolean updateState)
throws ModelException {
final String name = Messages.ScriptBuilder_scanningExternalFolders;
monitor.subTask(name);
final SubProgressMonitor mon = new SubProgressMonitor(monitor, tiks);
final IProjectFragment[] fragments = prj.getAllProjectFragments();
// new external fragments
final List extFragments = new ArrayList(fragments.length);
// external fragments paths
final List fragmentPaths = new ArrayList(fragments.length);
for (int i = 0; i < fragments.length; i++) {
final IProjectFragment fragment = fragments[i];
if (fragment.isExternal()) {
final IPath path = fragment.getPath();
if (!updateState
|| !this.lastState.externalFolderLocations
.contains(path)) {
extFragments.add(fragment);
} else {
fragmentPaths.add(path);
}
}
}
// monitor.subTask(name);
final ExternalModuleVisitor visitor = new ExternalModuleVisitor(mon);
mon.beginTask(name, extFragments.size());
for (Iterator iterator = extFragments.iterator(); iterator.hasNext();) {
IProjectFragment fragment = (IProjectFragment) iterator.next();
// New project fragment, we need to obtain all modules
// from this fragment.
fragment.accept(visitor);
if (updateState) {
fragmentPaths.add(fragment.getPath());
}
mon.worked(1);
}
mon.done();
if (updateState) {
this.lastState.externalFolderLocations.clear();
this.lastState.externalFolderLocations.addAll(fragmentPaths);
}
return visitor.elements;
}
protected void incrementalBuild(IResourceDelta delta,
IProgressMonitor monitor) throws CoreException {
State newState = new State(this);
Set externalFoldersBefore = new HashSet();
if (this.lastState != null) {
newState.copyFrom(this.lastState);
externalFoldersBefore.addAll(newState.getExternalFolders());
}
this.lastState = newState;
IScriptBuilder[] builders = null;
try {
monitor.setTaskName(NLS.bind(
Messages.ScriptBuilder_buildingScriptsIn, currentProject
.getName()));
monitor.beginTask(NONAME, WORK_RESOURCES + WORK_EXTERNAL
+ WORK_SOURCES + WORK_BUILD);
if (monitor.isCanceled()) {
return;
}
Set resources = getResourcesFrom(delta, monitor, WORK_RESOURCES);
if (monitor.isCanceled()) {
return;
}
if (DEBUG)
log("Number of changed resources in delta: " + resources.size()); //$NON-NLS-1$
Set externalElements = getExternalElementsFrom(scriptProject,
monitor, WORK_EXTERNAL, true);
// New external folders set
Set externalFolders = new HashSet(lastState.externalFolderLocations);
if (monitor.isCanceled()) {
return;
}
int totalFiles = resources.size() + externalElements.size();
if (totalFiles == 0)
totalFiles = 1;
builders = getScriptBuilders();
List localResources = new ArrayList();
List localElements = new ArrayList();
locateSourceModules(monitor, WORK_SOURCES, resources,
localElements, localResources);
if (monitor.isCanceled()) {
return;
}
int resourceTicks = WORK_BUILD
* (resources.size() - localElements.size()) / totalFiles;
if (monitor.isCanceled()) {
return;
}
try {
buildElements(localElements, externalElements, monitor,
WORK_BUILD - resourceTicks,
IScriptBuilder.INCREMENTAL_BUILD,
externalFoldersBefore, externalFolders, builders);
} catch (CoreException e) {
DLTKCore.error(Messages.ScriptBuilder_errorBuildElements, e);
}
lastBuildSourceFiles += externalElements.size();
if (monitor.isCanceled()) {
return;
}
buildResources(localResources, monitor, resourceTicks, FULL_BUILD,
builders);
lastBuildResources = resources.size() + externalElements.size();
} finally {
resetBuilders(builders);
monitor.done();
ModelManager.getModelManager().setLastBuiltState(currentProject,
this.lastState);
}
}
/**
* Return script builders for the current project. ScriptBuilders are
* initialized here so this method should be called only once during build
* operation.
*
* @return
* @throws CoreException
*/
private IScriptBuilder[] getScriptBuilders() throws CoreException {
IDLTKLanguageToolkit toolkit = DLTKLanguageManager
.getLanguageToolkit(scriptProject);
if (toolkit != null) {
IScriptBuilder[] builders = ScriptBuilderManager
.getScriptBuilders(toolkit.getNatureId());
if (builders != null) {
for (int k = 0; k < builders.length; k++) {
builders[k].initialize(scriptProject);
}
}
return builders;
} else {
return null;
}
}
/**
* Splits the <code>resources</code> into <code>realElements</code> and
* <code>realResources</code>
*
* @param monitor
* @param tiks
* @param resources
* @param realResources
* @return
*/
protected void locateSourceModules(IProgressMonitor monitor, int tiks,
Set resources, List realElements, List realResources) {
IProgressMonitor sub = new SubProgressMonitor(monitor, tiks / 3);
sub.beginTask(NONAME, resources.size());
int remainingWork = resources.size();
for (Iterator iterator = resources.iterator(); iterator.hasNext();) {
if (monitor.isCanceled()) {
return;
}
IResource res = (IResource) iterator.next();
sub.subTask(NLS.bind(
Messages.ScriptBuilder_Locating_source_modules, String
.valueOf(remainingWork), res.getName()));
sub.worked(1);
if (sub.isCanceled()) {
return;
}
IModelElement element = DLTKCore.create(res);
if (element != null
&& element.getElementType() == IModelElement.SOURCE_MODULE
&& element.exists()) {
realElements.add(element);
} else {
realResources.add(res);
}
--remainingWork;
}
sub.done();
lastBuildSourceFiles += realElements.size();
}
/**
* Build only resources, if some resources are elements they they will be
* returned.
*/
protected void buildResources(List realResources, IProgressMonitor monitor,
int tiks, int buildType, IScriptBuilder[] builders) {
if (builders == null || builders.length == 0 || realResources.isEmpty()) {
monitor.worked(tiks);
return;
}
final IProgressMonitor ssub = new SubProgressMonitor(monitor, tiks);
try {
ssub.beginTask(Messages.ScriptBuilder_building, builders.length);
for (int k = 0; k < builders.length; k++) {
builders[k].buildResources(scriptProject, realResources,
new SubProgressMonitor(ssub, 1), buildType);
}
} finally {
ssub.done();
}
}
protected void buildElements(List localElements, Set externalElements,
IProgressMonitor monitor, int ticks, int buildType,
Set externalFoldersBefore, Set externalFolders,
IScriptBuilder[] builders) throws CoreException {
// TODO: replace this stuff with multistatus
if (builders == null) {
return;
}
final int[] workEstimations = new int[builders.length];
final List[] builderToElements = new List[builders.length];
final List[] builderExternalElements = new List[builders.length];
final int[] buildTypes = new int[builders.length];
Arrays.fill(buildTypes, buildType);
estimateBuild(localElements, externalElements, externalFoldersBefore,
externalFolders, builders, workEstimations, builderToElements,
builderExternalElements, buildTypes);
int total = 0;
for (int k = 0; k < builders.length; k++) {
total += workEstimations[k];
}
for (int k = 0; k < builders.length; k++) {
if (monitor.isCanceled()) {
return;
}
final IScriptBuilder builder = builders[k];
int builderWork = workEstimations[k] * ticks / total;
final List buildExternalElements = builderExternalElements[k];
if (buildExternalElements != null
&& buildExternalElements.size() > 0
&& builder instanceof IScriptBuilderExtension) {
final int step = buildExternalElements.size() * ticks / total;
builderWork -= step;
monitor.subTask(NLS.bind(
Messages.ScriptBuilder_building_N_externalModules,
Integer.toString(buildExternalElements.size())));
((IScriptBuilderExtension) builder).buildExternalElements(
scriptProject, buildExternalElements,
new SubProgressMonitor(monitor, step), buildTypes[k]);
}
final List buildElementsList = builderToElements[k];
if (buildElementsList.size() > 0) {
final int step = buildElementsList.size() * ticks / total;
builderWork -= step;
monitor.subTask(NLS.bind(
Messages.ScriptBuilder_building_N_localModules, Integer
.toString(buildElementsList.size())));
builder.buildModelElements(scriptProject, buildElementsList,
new SubProgressMonitor(monitor, step), buildTypes[k]);
}
if (builderWork > 0) {
monitor.worked(builderWork);
}
}
// TODO: Do something with status.
}
/**
* Processes input data and fills the <code>workEstimations</code>,
* <code>builderToElements</code> and <code>builderExternalElements</code>
* arrays.
*
* @param localElements
* changed source modules
* @param externalElements
* newly added external source modules
* @param externalFoldersBefore
* old external fragments
* @param externalFolders
* new external fragments
* @param builders
* array of builders
* @param workEstimations
* arrays of work estimations
* @param builderToElements
* arrays of elements to be build by each builder
* @param builderExternalElements
* arrays of external elements to be build by each builder
* @param buildTypes
* resulting build types for each builder
* @throws CoreException
*/
private void estimateBuild(List localElements, Set externalElements,
Set externalFoldersBefore, Set externalFolders,
IScriptBuilder[] builders, final int[] workEstimations,
final List[] builderToElements, List[] builderExternalElements,
int[] buildTypes) throws CoreException {
final HashSet elementsAsSet = new HashSet(localElements);
List projectElements = null;
List projectExternalElements = null;
for (int k = 0; k < builders.length; k++) {
final IScriptBuilder builder = builders[k];
final IScriptBuilder.DependencyResponse response = builder
.getDependencies(this.scriptProject, buildTypes[k],
elementsAsSet, externalElements,
externalFoldersBefore, externalFolders);
final List buildElementsList;
final List buildExternalElements;
if (response == null) {
buildElementsList = localElements;
buildExternalElements = null;
} else {
if (response.isFullLocalBuild()) {
if (buildTypes[k] == IScriptBuilder.FULL_BUILD) {
buildElementsList = localElements;
} else {
if (projectElements == null) {
projectElements = collectLocalElements();
}
buildElementsList = projectElements;
}
} else {
final Set dependencies = response.getLocalDependencies();
if (dependencies != null && !dependencies.isEmpty()
&& !elementsAsSet.containsAll(dependencies)) {
final Set e = new HashSet(elementsAsSet.size()
+ dependencies.size());
e.addAll(elementsAsSet);
e.addAll(dependencies);
buildElementsList = new ArrayList(e);
} else {
buildElementsList = localElements;
}
}
if (response.isFullExternalBuild()) {
if (buildTypes[k] == IScriptBuilder.FULL_BUILD) {
buildExternalElements = new ArrayList(externalElements);
} else {
if (projectExternalElements == null) {
projectExternalElements = new ArrayList(
getExternalElementsFrom(scriptProject,
new NullProgressMonitor(), 1, false));
}
buildExternalElements = projectExternalElements;
}
} else {
final Set dependencies = response.getExternalDependencies();
if (dependencies != null && !dependencies.isEmpty()
&& !externalElements.containsAll(dependencies)) {
final Set e = new HashSet(externalElements.size()
+ dependencies.size());
e.addAll(externalElements);
e.addAll(dependencies);
buildExternalElements = new ArrayList(e);
} else {
buildExternalElements = null;
}
}
if (response.isFullLocalBuild()
|| response.isFullExternalBuild()) {
buildTypes[k] = IScriptBuilder.FULL_BUILD;
}
}
builderToElements[k] = buildElementsList;
builderExternalElements[k] = buildExternalElements;
int work = buildElementsList.size();
if (buildExternalElements != null) {
work += buildExternalElements.size();
}
workEstimations[k] = Math.max(work, 1);
}
}
private List collectLocalElements() throws CoreException {
final IProgressMonitor nullMon = new NullProgressMonitor();
final Set resources = getResourcesFrom(currentProject, nullMon, 1);
final List elements = new ArrayList();
locateSourceModules(nullMon, 1, resources, elements, new ArrayList());
return elements;
}
public static void removeProblemsAndTasksFor(IResource resource) {
try {
if (resource != null && resource.exists()) {
resource.deleteMarkers(
IModelMarker.SCRIPT_MODEL_PROBLEM_MARKER, false,
IResource.DEPTH_INFINITE);
resource.deleteMarkers(IModelMarker.TASK_MARKER, false,
IResource.DEPTH_INFINITE);
// delete managed markers
}
} catch (CoreException e) {
// assume there were no problems
}
}
public static void writeState(Object state, DataOutputStream out)
throws IOException {
((State) state).write(out);
}
public static State readState(IProject project, DataInputStream in)
throws IOException {
State state = State.read(project, in);
return state;
}
}