X-Git-Url: http://secure.phpeclipse.com
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/builder/PHPBuilder.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/builder/PHPBuilder.java
index 1bd843c..62fb231 100644
--- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/builder/PHPBuilder.java
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/builder/PHPBuilder.java
@@ -9,6 +9,7 @@
* IBM Corporation - initial API and implementation
*******************************************************************************/
package net.sourceforge.phpdt.internal.core.builder;
+
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
@@ -47,669 +48,752 @@ import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
public class PHPBuilder extends IncrementalProjectBuilder {
- IProject currentProject;
- JavaProject javaProject;
- IWorkspaceRoot workspaceRoot;
- NameEnvironment nameEnvironment;
- SimpleLookupTable binaryLocationsPerProject; // maps a project to its binary
- // resources (output folders,
- // class folders, zip/jar files)
- State lastState;
- BuildNotifier notifier;
- char[][] extraResourceFileFilters;
- String[] extraResourceFolderFilters;
- public static final String CLASS_EXTENSION = "class"; //$NON-NLS-1$
- public static boolean DEBUG = false;
- /**
- * A list of project names that have been built. This list is used to reset
- * the JavaModel.existingExternalFiles cache when a build cycle begins so
- * that deleted external jars are discovered.
- */
- static ArrayList builtProjects = null;
- public static IMarker[] getProblemsFor(IResource resource) {
- try {
- if (resource != null && resource.exists())
- return resource.findMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER,
- false, IResource.DEPTH_INFINITE);
- } catch (CoreException e) {
- } // assume there are no problems
- return new IMarker[0];
- }
- public static IMarker[] getTasksFor(IResource resource) {
- try {
- if (resource != null && resource.exists())
- return resource.findMarkers(IJavaModelMarker.TASK_MARKER, false,
- IResource.DEPTH_INFINITE);
- } catch (CoreException e) {
- } // assume there are no tasks
- return new IMarker[0];
- }
- public static void finishedBuilding(IResourceChangeEvent event) {
- BuildNotifier.resetProblemCounters();
- }
- /**
- * 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() {
- // do nothing
- // TODO (philippe) is it still needed?
- }
-
- /**
- * 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() {
- BuildNotifier.resetProblemCounters();
- }
- public static void removeProblemsFor(IResource resource) {
- try {
- if (resource != null && resource.exists())
- resource.deleteMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER,
- false, IResource.DEPTH_INFINITE);
- } catch (CoreException e) {
- } // assume there were no problems
- }
- public static void removeTasksFor(IResource resource) {
- try {
- if (resource != null && resource.exists())
- resource.deleteMarkers(IJavaModelMarker.TASK_MARKER, false,
- IResource.DEPTH_INFINITE);
- } catch (CoreException e) {
- } // assume there were no problems
- }
- public static void removeProblemsAndTasksFor(IResource resource) {
- try {
- if (resource != null && resource.exists()) {
- resource.deleteMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER,
- false, IResource.DEPTH_INFINITE);
- resource.deleteMarkers(IJavaModelMarker.TASK_MARKER, false,
- IResource.DEPTH_INFINITE);
- }
- } catch (CoreException e) {
- } // assume there were no problems
- }
- public static State readState(IProject project, DataInputStream in)
- throws IOException {
- return State.read(project, in);
- }
- public static void writeState(Object state, DataOutputStream out)
- throws IOException {
- ((State) state).write(out);
- }
- public PHPBuilder() {
- }
- protected IProject[] build(int kind, Map ignored, IProgressMonitor monitor)
- throws CoreException {
- this.currentProject = getProject();
- if (currentProject == null || !currentProject.isAccessible())
- return new IProject[0];
- if (DEBUG)
- System.out.println("\nStarting build of " + currentProject.getName() //$NON-NLS-1$
- + " @ " + new Date(System.currentTimeMillis())); //$NON-NLS-1$
- this.notifier = new BuildNotifier(monitor, currentProject);
- notifier.begin();
- boolean ok = false;
- try {
- notifier.checkCancel();
- initializeBuilder();
- if (isWorthBuilding()) {
- if (kind == FULL_BUILD) {
- processFullPHPIndex(currentProject, monitor);
- buildAll();
- } else {
- if ((this.lastState = getLastState(currentProject)) == null) {
- if (DEBUG)
- System.out
- .println("Performing full build since last saved state was not found"); //$NON-NLS-1$
- processFullPHPIndex(currentProject, monitor);
- buildAll();
-// } else if (hasClasspathChanged()) {
-// // if the output location changes, do not delete the binary files
-// // from old location
-// // the user may be trying something
-// buildAll();
- } else if (nameEnvironment.sourceLocations.length > 0) {
- // if there is no source to compile & no classpath changes then we
- // are done
- SimpleLookupTable deltas = findDeltas();
- if (deltas == null)
- buildAll();
- else if (deltas.elementSize > 0)
- buildDeltas(deltas);
- else if (DEBUG)
- System.out.println("Nothing to build since deltas were empty"); //$NON-NLS-1$
- } else {
- if (hasStructuralDelta()) { // double check that a jar file didn't
- // get replaced in a binary project
- processFullPHPIndex(currentProject, monitor);
- buildAll();
- } else {
- if (DEBUG)
- System.out
- .println("Nothing to build since there are no source folders and no deltas"); //$NON-NLS-1$
- lastState.tagAsNoopBuild();
- }
- }
- }
- ok = true;
- }
- } catch (CoreException e) {
- Util.log(e, "JavaBuilder handling CoreException"); //$NON-NLS-1$
- IMarker marker = currentProject
- .createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
- marker.setAttribute(IMarker.MESSAGE, Util.bind(
- "build.inconsistentProject", e.getLocalizedMessage())); //$NON-NLS-1$
- marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
- } catch (ImageBuilderInternalException e) {
- Util.log(e.getThrowable(),
- "JavaBuilder handling ImageBuilderInternalException"); //$NON-NLS-1$
- IMarker marker = currentProject
- .createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
- marker.setAttribute(IMarker.MESSAGE, Util.bind(
- "build.inconsistentProject", e.coreException.getLocalizedMessage())); //$NON-NLS-1$
- marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
- } catch (MissingClassFileException e) {
- // do not log this exception since its thrown to handle aborted compiles
- // because of missing class files
- if (DEBUG)
- System.out.println(Util.bind("build.incompleteClassPath",
- e.missingClassFile)); //$NON-NLS-1$
- IMarker marker = currentProject
- .createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
- marker.setAttribute(IMarker.MESSAGE, Util.bind(
- "build.incompleteClassPath", e.missingClassFile)); //$NON-NLS-1$
- marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
- } catch (MissingSourceFileException e) {
- // do not log this exception since its thrown to handle aborted compiles
- // because of missing source files
- if (DEBUG)
- System.out.println(Util.bind("build.missingSourceFile",
- e.missingSourceFile)); //$NON-NLS-1$
- removeProblemsAndTasksFor(currentProject); // make this the only problem
- // for this project
- IMarker marker = currentProject
- .createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
- marker.setAttribute(IMarker.MESSAGE, Util.bind("build.missingSourceFile",
- e.missingSourceFile)); //$NON-NLS-1$
- marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- if (!ok)
- // If the build failed, clear the previously built state, forcing a
- // full build next time.
- clearLastState();
- notifier.done();
- cleanup();
- }
- IProject[] requiredProjects = getRequiredProjects(true);
- if (DEBUG)
- System.out.println("Finished build of " + currentProject.getName() //$NON-NLS-1$
- + " @ " + new Date(System.currentTimeMillis())); //$NON-NLS-1$
- return requiredProjects;
- }
- /**
- * Performs a FULL_BUILD
by visiting all nodes in the resource
- * tree under the specified project.
- *
- * @param iProject
- */
- private void processFullPHPIndex(final IProject iProject,
- final IProgressMonitor monitor) {
- final IdentifierIndexManager indexManager = PHPeclipsePlugin.getDefault()
- .getIndexManager(iProject);
- // Create resource visitor logic
- IResourceVisitor myVisitor = new IResourceVisitor() {
- public boolean visit(IResource resource) throws CoreException {
- if (resource.getType() == IResource.FILE) {
- if (monitor.isCanceled()) {
- throw new OperationCanceledException();
- }
- if ((resource.getFileExtension() != null)
- && PHPFileUtil.isPHPFile((IFile) resource)) {
- monitor.worked(1);
- monitor.subTask("Parsing: " + resource.getFullPath());
- // update indexfile for the project:
-// PHPProject nature = (PHPProject) iProject
-// .getNature(PHPeclipsePlugin.PHP_NATURE_ID);
- indexManager.addFile((IFile) resource);
- }
- }
- return true;
- }
- };
- // Process the project using the visitor just created
- try {
- // if (iProject.hasNature(PHPeclipsePlugin.PHP_NATURE_ID)) {
- // thePHPProject = new PHPProject();
- // thePHPProject.setProject(iProject);
- // }
- indexManager.initialize();
- iProject.accept(myVisitor);
- indexManager.writeFile();
- } catch (CoreException e) {
- e.printStackTrace();
- }
- }
- private void buildAll() {
- notifier.checkCancel();
- notifier.subTask(Util.bind("build.preparingBuild")); //$NON-NLS-1$
- if (DEBUG && lastState != null)
- System.out.println("Clearing last state : " + lastState); //$NON-NLS-1$
- clearLastState();
- BatchImageBuilder imageBuilder = new BatchImageBuilder(this);
- imageBuilder.build();
- recordNewState(imageBuilder.newState);
- }
- private void buildDeltas(SimpleLookupTable deltas) {
- notifier.checkCancel();
- notifier.subTask(Util.bind("build.preparingBuild")); //$NON-NLS-1$
- if (DEBUG && lastState != null)
- System.out.println("Clearing last state : " + lastState); //$NON-NLS-1$
- clearLastState(); // clear the previously built state so if the build
- // fails, a full build will occur next time
- IncrementalImageBuilder imageBuilder = new IncrementalImageBuilder(this);
- if (imageBuilder.build(deltas))
- recordNewState(imageBuilder.newState);
- else {
- processFullPHPIndex(currentProject, notifier.monitor);
- buildAll();
- }
- }
- private void cleanup() {
- this.nameEnvironment = null;
- this.binaryLocationsPerProject = null;
- this.lastState = null;
- this.notifier = null;
- this.extraResourceFileFilters = null;
- this.extraResourceFolderFilters = null;
- }
- private void clearLastState() {
- JavaModelManager.getJavaModelManager().setLastBuiltState(currentProject,
- null);
- }
- boolean filterExtraResource(IResource resource) {
- if (extraResourceFileFilters != null) {
- char[] name = resource.getName().toCharArray();
- for (int i = 0, l = extraResourceFileFilters.length; i < l; i++)
- if (CharOperation.match(extraResourceFileFilters[i], name, true))
- return true;
- }
- if (extraResourceFolderFilters != null) {
- IPath path = resource.getProjectRelativePath();
- String pathName = path.toString();
- int count = path.segmentCount();
- if (resource.getType() == IResource.FILE)
- count--;
- for (int i = 0, l = extraResourceFolderFilters.length; i < l; i++)
- if (pathName.indexOf(extraResourceFolderFilters[i]) != -1)
- for (int j = 0; j < count; j++)
- if (extraResourceFolderFilters[i].equals(path.segment(j)))
- return true;
- }
- return false;
- }
- private SimpleLookupTable findDeltas() {
- notifier.subTask(Util.bind("build.readingDelta", currentProject.getName())); //$NON-NLS-1$
- IResourceDelta delta = getDelta(currentProject);
- SimpleLookupTable deltas = new SimpleLookupTable(3);
- if (delta != null) {
- if (delta.getKind() != IResourceDelta.NO_CHANGE) {
- if (DEBUG)
- System.out.println("Found source delta for: "
- + currentProject.getName()); //$NON-NLS-1$
- deltas.put(currentProject, delta);
- }
- } else {
- if (DEBUG)
- System.out.println("Missing delta for: " + currentProject.getName()); //$NON-NLS-1$
- notifier.subTask(""); //$NON-NLS-1$
- return null;
- }
- Object[] keyTable = binaryLocationsPerProject.keyTable;
- Object[] valueTable = binaryLocationsPerProject.valueTable;
- nextProject : for (int i = 0, l = keyTable.length; i < l; i++) {
- IProject p = (IProject) keyTable[i];
- if (p != null && p != currentProject) {
- State s = getLastState(p);
- if (!lastState.wasStructurallyChanged(p, s)) { // see if we can skip
- // its delta
- if (s.wasNoopBuild())
- continue nextProject; // project has no source folders and can be
- // skipped
- // ClasspathLocation[] classFoldersAndJars = (ClasspathLocation[])
- // valueTable[i];
- boolean canSkip = true;
- // for (int j = 0, m = classFoldersAndJars.length; j < m; j++) {
- // if (classFoldersAndJars[j].isOutputFolder())
- // classFoldersAndJars[j] = null; // can ignore output folder since
- // project was not structurally changed
- // else
- // canSkip = false;
- // }
- if (canSkip)
- continue nextProject; // project has no structural changes in its
- // output folders
- }
- notifier.subTask(Util.bind("build.readingDelta", p.getName())); //$NON-NLS-1$
- delta = getDelta(p);
- if (delta != null) {
- if (delta.getKind() != IResourceDelta.NO_CHANGE) {
- if (DEBUG)
- System.out.println("Found binary delta for: " + p.getName()); //$NON-NLS-1$
- deltas.put(p, delta);
- }
- } else {
- if (DEBUG)
- System.out.println("Missing delta for: " + p.getName()); //$NON-NLS-1$
- notifier.subTask(""); //$NON-NLS-1$
- return null;
- }
- }
- }
- notifier.subTask(""); //$NON-NLS-1$
- return deltas;
- }
- private State getLastState(IProject project) {
- return (State) JavaModelManager.getJavaModelManager().getLastBuiltState(
- project, notifier.monitor);
- }
- /*
- * Return the list of projects for which it requires a resource delta. This
- * builder's project is implicitly included and need not be specified.
- * Builders must re-specify the list of interesting projects every time they
- * are run as this is not carried forward beyond the next build. Missing
- * projects should be specified but will be ignored until they are added to
- * the workspace.
- */
- private IProject[] getRequiredProjects(boolean includeBinaryPrerequisites) {
- if (javaProject == null || workspaceRoot == null)
- return new IProject[0];
- ArrayList projects = new ArrayList();
- try {
- IClasspathEntry[] entries = javaProject.getExpandedClasspath(true);
- for (int i = 0, l = entries.length; i < l; i++) {
- IClasspathEntry entry = entries[i];
- IPath path = entry.getPath();
- IProject p = null;
- switch (entry.getEntryKind()) {
- case IClasspathEntry.CPE_PROJECT :
- p = workspaceRoot.getProject(path.lastSegment()); // missing
- // projects are
- // considered too
- break;
- case IClasspathEntry.CPE_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 (JavaModelException e) {
- return new IProject[0];
- }
- IProject[] result = new IProject[projects.size()];
- projects.toArray(result);
- return result;
- }
-// private boolean hasClasspathChanged() {
-// ClasspathMultiDirectory[] newSourceLocations = nameEnvironment.sourceLocations;
-// ClasspathMultiDirectory[] oldSourceLocations = lastState.sourceLocations;
-// int newLength = newSourceLocations.length;
-// int oldLength = oldSourceLocations.length;
-// int n, o;
-// for (n = o = 0; n < newLength && o < oldLength; n++, o++) {
-// if (newSourceLocations[n].equals(oldSourceLocations[o]))
-// continue; // checks source & output folders
-// try {
-// if (newSourceLocations[n].sourceFolder.members().length == 0) { // added
-// // new
-// // empty
-// // source
-// // folder
-// o--;
-// continue;
-// }
-// } catch (CoreException ignore) {
-// }
-// if (DEBUG)
-// System.out.println(newSourceLocations[n] + " != "
-// + oldSourceLocations[o]); //$NON-NLS-1$
-// return true;
-// }
-// while (n < newLength) {
-// try {
-// if (newSourceLocations[n].sourceFolder.members().length == 0) { // added
-// // new
-// // empty
-// // source
-// // folder
-// n++;
-// continue;
-// }
-// } catch (CoreException ignore) {
-// }
-// if (DEBUG)
-// System.out.println("Added non-empty source folder"); //$NON-NLS-1$
-// return true;
-// }
-// if (o < oldLength) {
-// if (DEBUG)
-// System.out.println("Removed source folder"); //$NON-NLS-1$
-// return true;
-// }
-// // ClasspathLocation[] newBinaryLocations =
-// // nameEnvironment.binaryLocations;
-// // ClasspathLocation[] oldBinaryLocations = lastState.binaryLocations;
-// // newLength = newBinaryLocations.length;
-// // oldLength = oldBinaryLocations.length;
-// // for (n = o = 0; n < newLength && o < oldLength; n++, o++) {
-// // if (newBinaryLocations[n].equals(oldBinaryLocations[o])) continue;
-// // if (DEBUG)
-// // System.out.println(newBinaryLocations[n] + " != " +
-// // oldBinaryLocations[o]); //$NON-NLS-1$
-// // return true;
-// // }
-// // if (n < newLength || o < oldLength) {
-// // if (DEBUG)
-// // System.out.println("Number of binary folders/jar files has changed");
-// // //$NON-NLS-1$
-// // return true;
-// // }
-// return false;
-// }
- private boolean hasStructuralDelta() {
- // handle case when currentProject has only .class file folders and/or jar
- // files... no source/output folders
- IResourceDelta delta = getDelta(currentProject);
- if (delta != null && delta.getKind() != IResourceDelta.NO_CHANGE) {
- // ClasspathLocation[] classFoldersAndJars = (ClasspathLocation[])
- // binaryLocationsPerProject.get(currentProject);
- // if (classFoldersAndJars != null) {
- // for (int i = 0, l = classFoldersAndJars.length; i < l; i++) {
- // ClasspathLocation classFolderOrJar = classFoldersAndJars[i]; // either
- // a .class file folder or a zip/jar file
- // if (classFolderOrJar != null) {
- // IPath p = classFolderOrJar.getProjectRelativePath();
- // if (p != null) {
- // IResourceDelta binaryDelta = delta.findMember(p);
- // if (binaryDelta != null && binaryDelta.getKind() !=
- // IResourceDelta.NO_CHANGE)
- // return true;
- // }
- // }
- // }
- // }
- }
- return false;
- }
- private void initializeBuilder() throws CoreException {
- this.javaProject = (JavaProject) JavaCore.create(currentProject);
- this.workspaceRoot = currentProject.getWorkspace().getRoot();
- // Flush the existing external files cache if this is the beginning of a
- // build cycle
- String projectName = currentProject.getName();
- if (builtProjects == null || builtProjects.contains(projectName)) {
- JavaModel.flushExternalFileCache();
- builtProjects = new ArrayList();
- }
- builtProjects.add(projectName);
- this.binaryLocationsPerProject = new SimpleLookupTable(3);
- this.nameEnvironment = new NameEnvironment(workspaceRoot, javaProject,
- binaryLocationsPerProject);
- String filterSequence = javaProject.getOption(
- JavaCore.CORE_JAVA_BUILD_RESOURCE_COPY_FILTER, true);
- char[][] filters = filterSequence != null && filterSequence.length() > 0
- ? CharOperation.splitAndTrimOn(',', filterSequence.toCharArray())
- : null;
- if (filters == null) {
- this.extraResourceFileFilters = null;
- this.extraResourceFolderFilters = null;
- } else {
- int fileCount = 0, folderCount = 0;
- for (int i = 0, l = filters.length; i < l; i++) {
- char[] f = filters[i];
- if (f.length == 0)
- continue;
- if (f[f.length - 1] == '/')
- folderCount++;
- else
- fileCount++;
- }
- this.extraResourceFileFilters = new char[fileCount][];
- this.extraResourceFolderFilters = new String[folderCount];
- for (int i = 0, l = filters.length; i < l; i++) {
- char[] f = filters[i];
- if (f.length == 0)
- continue;
- if (f[f.length - 1] == '/')
- extraResourceFolderFilters[--folderCount] = new String(CharOperation
- .subarray(f, 0, f.length - 1));
- else
- extraResourceFileFilters[--fileCount] = f;
- }
- }
- }
- private boolean isClasspathBroken(IClasspathEntry[] classpath, IProject p)
- throws CoreException {
- if (classpath == JavaProject.INVALID_CLASSPATH) // the .classpath file
- // could not be read
- return true;
- IMarker[] markers = p.findMarkers(
- IJavaModelMarker.BUILDPATH_PROBLEM_MARKER, false, IResource.DEPTH_ZERO);
- for (int i = 0, l = markers.length; i < l; i++)
- if (((Integer) markers[i].getAttribute(IMarker.SEVERITY)).intValue() == IMarker.SEVERITY_ERROR)
- return true;
- return false;
- }
- private boolean isWorthBuilding() throws CoreException {
- boolean abortBuilds = JavaCore.ABORT.equals(javaProject.getOption(
- JavaCore.CORE_JAVA_BUILD_INVALID_CLASSPATH, true));
- if (!abortBuilds)
- return true;
- // Abort build only if there are classpath errors
- // if (isClasspathBroken(javaProject.getRawClasspath(), currentProject)) {
- // if (DEBUG)
- // System.out.println("Aborted build because project has classpath errors
- // (incomplete or involved in cycle)"); //$NON-NLS-1$
- //
- // JavaModelManager.getJavaModelManager().deltaProcessor.addForRefresh(javaProject);
- //
- // removeProblemsAndTasksFor(currentProject); // remove all compilation
- // problems
- //
- // IMarker marker =
- // currentProject.createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
- // marker.setAttribute(IMarker.MESSAGE,
- // Util.bind("build.abortDueToClasspathProblems")); //$NON-NLS-1$
- // marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
- // return false;
- // }
- // make sure all prereq projects have valid build states... only when
- // aborting builds since projects in cycles do not have build states
- // except for projects involved in a 'warning' cycle (see below)
- IProject[] requiredProjects = getRequiredProjects(false);
- next : for (int i = 0, l = requiredProjects.length; i < l; i++) {
- IProject p = requiredProjects[i];
- if (getLastState(p) == null) {
- // The prereq project has no build state: if this prereq project has a
- // 'warning' cycle marker then allow build (see bug id 23357)
- JavaProject prereq = (JavaProject) JavaCore.create(p);
- if (prereq.hasCycleMarker()
- && JavaCore.WARNING.equals(javaProject.getOption(
- JavaCore.CORE_CIRCULAR_CLASSPATH, true)))
- continue;
- if (DEBUG)
- System.out.println("Aborted build because prereq project "
- + p.getName() //$NON-NLS-1$
- + " was not built"); //$NON-NLS-1$
- removeProblemsAndTasksFor(currentProject); // make this the only
- // problem for this project
- IMarker marker = currentProject
- .createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
- marker.setAttribute(IMarker.MESSAGE, isClasspathBroken(prereq
- .getRawClasspath(), p) ? Util.bind(
- "build.prereqProjectHasClasspathProblems", p.getName()) //$NON-NLS-1$
- : Util.bind("build.prereqProjectMustBeRebuilt", p.getName())); //$NON-NLS-1$
- marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
- return false;
- }
- }
- return true;
- }
- /*
- * Instruct the build manager that this project is involved in a cycle and
- * needs to propagate structural changes to the other projects in the cycle.
- */
- void mustPropagateStructuralChanges() {
- HashSet cycleParticipants = new HashSet(3);
- javaProject.updateCycleParticipants(null, new ArrayList(),
- cycleParticipants, workspaceRoot, new HashSet(3));
- IPath currentPath = javaProject.getPath();
- Iterator i = cycleParticipants.iterator();
- while (i.hasNext()) {
- IPath participantPath = (IPath) i.next();
- if (participantPath != currentPath) {
- IProject project = this.workspaceRoot.getProject(participantPath
- .segment(0));
- if (hasBeenBuilt(project)) {
- if (DEBUG)
- System.out
- .println("Requesting another build iteration since cycle participant "
- + project.getName() //$NON-NLS-1$
- + " has not yet seen some structural changes"); //$NON-NLS-1$
- needRebuild();
- return;
- }
- }
- }
- }
- private void recordNewState(State state) {
- Object[] keyTable = binaryLocationsPerProject.keyTable;
- for (int i = 0, l = keyTable.length; i < l; i++) {
- IProject prereqProject = (IProject) keyTable[i];
- if (prereqProject != null && prereqProject != currentProject)
- state.recordStructuralDependency(prereqProject,
- getLastState(prereqProject));
- }
- if (DEBUG)
- System.out.println("Recording new state : " + state); //$NON-NLS-1$
- // state.dump();
- JavaModelManager.getJavaModelManager().setLastBuiltState(currentProject,
- state);
- }
- /**
- * String representation for debugging purposes
- */
- public String toString() {
- return currentProject == null ? "JavaBuilder for unknown project" //$NON-NLS-1$
- : "JavaBuilder for " + currentProject.getName(); //$NON-NLS-1$
- }
+ IProject currentProject;
+
+ JavaProject javaProject;
+
+ IWorkspaceRoot workspaceRoot;
+
+ NameEnvironment nameEnvironment;
+
+ SimpleLookupTable binaryLocationsPerProject; // maps a project to its
+ // binary
+
+ // resources (output folders,
+ // class folders, zip/jar files)
+ State lastState;
+
+ BuildNotifier notifier;
+
+ char[][] extraResourceFileFilters;
+
+ String[] extraResourceFolderFilters;
+
+ public static final String CLASS_EXTENSION = "class"; //$NON-NLS-1$
+
+ public static boolean DEBUG = false;
+
+ /**
+ * A list of project names that have been built. This list is used to reset
+ * the JavaModel.existingExternalFiles cache when a build cycle begins so
+ * that deleted external jars are discovered.
+ */
+ static ArrayList builtProjects = null;
+
+ public static IMarker[] getProblemsFor(IResource resource) {
+ try {
+ if (resource != null && resource.exists())
+ return resource.findMarkers(
+ IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, false,
+ IResource.DEPTH_INFINITE);
+ } catch (CoreException e) {
+ } // assume there are no problems
+ return new IMarker[0];
+ }
+
+ public static IMarker[] getTasksFor(IResource resource) {
+ try {
+ if (resource != null && resource.exists())
+ return resource.findMarkers(IJavaModelMarker.TASK_MARKER,
+ false, IResource.DEPTH_INFINITE);
+ } catch (CoreException e) {
+ } // assume there are no tasks
+ return new IMarker[0];
+ }
+
+ public static void finishedBuilding(IResourceChangeEvent event) {
+ BuildNotifier.resetProblemCounters();
+ }
+
+ /**
+ * 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() {
+ // do nothing
+ // TODO (philippe) is it still needed?
+ }
+
+ /**
+ * 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() {
+ BuildNotifier.resetProblemCounters();
+ }
+
+ public static void removeProblemsFor(IResource resource) {
+ try {
+ if (resource != null && resource.exists())
+ resource.deleteMarkers(
+ IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, false,
+ IResource.DEPTH_INFINITE);
+ } catch (CoreException e) {
+ } // assume there were no problems
+ }
+
+ public static void removeTasksFor(IResource resource) {
+ try {
+ if (resource != null && resource.exists())
+ resource.deleteMarkers(IJavaModelMarker.TASK_MARKER, false,
+ IResource.DEPTH_INFINITE);
+ } catch (CoreException e) {
+ } // assume there were no problems
+ }
+
+ public static void removeProblemsAndTasksFor(IResource resource) {
+ try {
+ if (resource != null && resource.exists()) {
+ resource.deleteMarkers(
+ IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, false,
+ IResource.DEPTH_INFINITE);
+ resource.deleteMarkers(IJavaModelMarker.TASK_MARKER, false,
+ IResource.DEPTH_INFINITE);
+ }
+ } catch (CoreException e) {
+ } // assume there were no problems
+ }
+
+ public static State readState(IProject project, DataInputStream in)
+ throws IOException {
+ return State.read(project, in);
+ }
+
+ public static void writeState(Object state, DataOutputStream out)
+ throws IOException {
+ ((State) state).write(out);
+ }
+
+ public PHPBuilder() {
+ }
+
+ protected IProject[] build(int kind, Map ignored, IProgressMonitor monitor)
+ throws CoreException {
+ this.currentProject = getProject();
+ if (currentProject == null || !currentProject.isAccessible())
+ return new IProject[0];
+ if (DEBUG)
+ System.out
+ .println("\nStarting build of " + currentProject.getName() //$NON-NLS-1$
+ + " @ " + new Date(System.currentTimeMillis())); //$NON-NLS-1$
+ this.notifier = new BuildNotifier(monitor, currentProject);
+ notifier.begin();
+ boolean ok = false;
+ try {
+ notifier.checkCancel();
+ initializeBuilder();
+ if (isWorthBuilding()) {
+ if (kind == FULL_BUILD) {
+ processFullPHPIndex(currentProject, monitor);
+ buildAll();
+ } else {
+ if ((this.lastState = getLastState(currentProject)) == null) {
+ if (DEBUG)
+ System.out
+ .println("Performing full build since last saved state was not found"); //$NON-NLS-1$
+ processFullPHPIndex(currentProject, monitor);
+ buildAll();
+ // } else if (hasClasspathChanged()) {
+ // // if the output location changes, do not delete the
+ // binary files
+ // // from old location
+ // // the user may be trying something
+ // buildAll();
+ } else if (nameEnvironment.sourceLocations.length > 0) {
+ // if there is no source to compile & no classpath
+ // changes then we
+ // are done
+ SimpleLookupTable deltas = findDeltas();
+ if (deltas == null)
+ buildAll();
+ else if (deltas.elementSize > 0)
+ buildDeltas(deltas);
+ else if (DEBUG)
+ System.out
+ .println("Nothing to build since deltas were empty"); //$NON-NLS-1$
+ } else {
+ if (hasStructuralDelta()) { // double check that a jar
+ // file didn't
+ // get replaced in a binary project
+ processFullPHPIndex(currentProject, monitor);
+ buildAll();
+ } else {
+ if (DEBUG)
+ System.out
+ .println("Nothing to build since there are no source folders and no deltas"); //$NON-NLS-1$
+ lastState.tagAsNoopBuild();
+ }
+ }
+ }
+ ok = true;
+ }
+ } catch (CoreException e) {
+ Util.log(e, "JavaBuilder handling CoreException"); //$NON-NLS-1$
+ IMarker marker = currentProject
+ .createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
+ marker.setAttribute(IMarker.MESSAGE, Util.bind(
+ "build.inconsistentProject", e.getLocalizedMessage())); //$NON-NLS-1$
+ marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
+ } catch (ImageBuilderInternalException e) {
+ Util.log(e.getThrowable(),
+ "JavaBuilder handling ImageBuilderInternalException"); //$NON-NLS-1$
+ IMarker marker = currentProject
+ .createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
+ marker
+ .setAttribute(
+ IMarker.MESSAGE,
+ Util
+ .bind(
+ "build.inconsistentProject", e.coreException.getLocalizedMessage())); //$NON-NLS-1$
+ marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
+ } catch (MissingClassFileException e) {
+ // do not log this exception since its thrown to handle aborted
+ // compiles
+ // because of missing class files
+ if (DEBUG)
+ System.out.println(Util.bind("build.incompleteClassPath",
+ e.missingClassFile)); //$NON-NLS-1$
+ IMarker marker = currentProject
+ .createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
+ marker.setAttribute(IMarker.MESSAGE, Util.bind(
+ "build.incompleteClassPath", e.missingClassFile)); //$NON-NLS-1$
+ marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
+ } catch (MissingSourceFileException e) {
+ // do not log this exception since its thrown to handle aborted
+ // compiles
+ // because of missing source files
+ if (DEBUG)
+ System.out.println(Util.bind("build.missingSourceFile",
+ e.missingSourceFile)); //$NON-NLS-1$
+ removeProblemsAndTasksFor(currentProject); // make this the only
+ // problem
+ // for this project
+ IMarker marker = currentProject
+ .createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
+ marker.setAttribute(IMarker.MESSAGE, Util.bind(
+ "build.missingSourceFile", e.missingSourceFile)); //$NON-NLS-1$
+ marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ if (!ok)
+ // If the build failed, clear the previously built state,
+ // forcing a
+ // full build next time.
+ clearLastState();
+ notifier.done();
+ cleanup();
+ }
+ IProject[] requiredProjects = getRequiredProjects(true);
+ if (DEBUG)
+ System.out.println("Finished build of " + currentProject.getName() //$NON-NLS-1$
+ + " @ " + new Date(System.currentTimeMillis())); //$NON-NLS-1$
+ return requiredProjects;
+ }
+
+ /**
+ * Performs a FULL_BUILD
by visiting all nodes in the
+ * resource tree under the specified project.
+ *
+ * @param iProject
+ */
+ private void processFullPHPIndex(final IProject iProject,
+ final IProgressMonitor monitor) {
+ final IdentifierIndexManager indexManager = PHPeclipsePlugin
+ .getDefault().getIndexManager(iProject);
+ // Create resource visitor logic
+ IResourceVisitor myVisitor = new IResourceVisitor() {
+ public boolean visit(IResource resource) throws CoreException {
+ if (resource.getType() == IResource.FILE) {
+ if (monitor.isCanceled()) {
+ throw new OperationCanceledException();
+ }
+ if ((resource.getFileExtension() != null)
+ && PHPFileUtil.isPHPFile((IFile) resource)) {
+ monitor.worked(1);
+ monitor.subTask("Parsing: " + resource.getFullPath());
+ // update indexfile for the project:
+ // PHPProject nature = (PHPProject) iProject
+ // .getNature(PHPeclipsePlugin.PHP_NATURE_ID);
+ indexManager.addFile((IFile) resource);
+ }
+ }
+ return true;
+ }
+ };
+ // Process the project using the visitor just created
+ try {
+ // if (iProject.hasNature(PHPeclipsePlugin.PHP_NATURE_ID)) {
+ // thePHPProject = new PHPProject();
+ // thePHPProject.setProject(iProject);
+ // }
+ indexManager.initialize();
+ iProject.accept(myVisitor);
+ indexManager.writeFile();
+ } catch (CoreException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void buildAll() {
+ notifier.checkCancel();
+ notifier.subTask(Util.bind("build.preparingBuild")); //$NON-NLS-1$
+ if (DEBUG && lastState != null)
+ System.out.println("Clearing last state : " + lastState); //$NON-NLS-1$
+ clearLastState();
+ BatchImageBuilder imageBuilder = new BatchImageBuilder(this);
+ imageBuilder.build();
+ recordNewState(imageBuilder.newState);
+ }
+
+ private void buildDeltas(SimpleLookupTable deltas) {
+ notifier.checkCancel();
+ notifier.subTask(Util.bind("build.preparingBuild")); //$NON-NLS-1$
+ if (DEBUG && lastState != null)
+ System.out.println("Clearing last state : " + lastState); //$NON-NLS-1$
+ clearLastState(); // clear the previously built state so if the build
+ // fails, a full build will occur next time
+ IncrementalImageBuilder imageBuilder = new IncrementalImageBuilder(this);
+ if (imageBuilder.build(deltas))
+ recordNewState(imageBuilder.newState);
+ else {
+ processFullPHPIndex(currentProject, notifier.monitor);
+ buildAll();
+ }
+ }
+
+ private void cleanup() {
+ this.nameEnvironment = null;
+ this.binaryLocationsPerProject = null;
+ this.lastState = null;
+ this.notifier = null;
+ this.extraResourceFileFilters = null;
+ this.extraResourceFolderFilters = null;
+ }
+
+ private void clearLastState() {
+ JavaModelManager.getJavaModelManager().setLastBuiltState(
+ currentProject, null);
+ }
+
+ boolean filterExtraResource(IResource resource) {
+ if (extraResourceFileFilters != null) {
+ char[] name = resource.getName().toCharArray();
+ for (int i = 0, l = extraResourceFileFilters.length; i < l; i++)
+ if (CharOperation
+ .match(extraResourceFileFilters[i], name, true))
+ return true;
+ }
+ if (extraResourceFolderFilters != null) {
+ IPath path = resource.getProjectRelativePath();
+ String pathName = path.toString();
+ int count = path.segmentCount();
+ if (resource.getType() == IResource.FILE)
+ count--;
+ for (int i = 0, l = extraResourceFolderFilters.length; i < l; i++)
+ if (pathName.indexOf(extraResourceFolderFilters[i]) != -1)
+ for (int j = 0; j < count; j++)
+ if (extraResourceFolderFilters[i].equals(path
+ .segment(j)))
+ return true;
+ }
+ return false;
+ }
+
+ private SimpleLookupTable findDeltas() {
+ notifier.subTask(Util.bind(
+ "build.readingDelta", currentProject.getName())); //$NON-NLS-1$
+ IResourceDelta delta = getDelta(currentProject);
+ SimpleLookupTable deltas = new SimpleLookupTable(3);
+ if (delta != null) {
+ if (delta.getKind() != IResourceDelta.NO_CHANGE) {
+ if (DEBUG)
+ System.out.println("Found source delta for: "
+ + currentProject.getName()); //$NON-NLS-1$
+ deltas.put(currentProject, delta);
+ }
+ } else {
+ if (DEBUG)
+ System.out
+ .println("Missing delta for: " + currentProject.getName()); //$NON-NLS-1$
+ notifier.subTask(""); //$NON-NLS-1$
+ return null;
+ }
+ Object[] keyTable = binaryLocationsPerProject.keyTable;
+ Object[] valueTable = binaryLocationsPerProject.valueTable;
+ nextProject: for (int i = 0, l = keyTable.length; i < l; i++) {
+ IProject p = (IProject) keyTable[i];
+ if (p != null && p != currentProject) {
+ State s = getLastState(p);
+ if (!lastState.wasStructurallyChanged(p, s)) { // see if we can
+ // skip
+ // its delta
+ if (s.wasNoopBuild())
+ continue nextProject; // project has no source folders
+ // and can be
+ // skipped
+ // ClasspathLocation[] classFoldersAndJars =
+ // (ClasspathLocation[])
+ // valueTable[i];
+ boolean canSkip = true;
+ // for (int j = 0, m = classFoldersAndJars.length; j < m;
+ // j++) {
+ // if (classFoldersAndJars[j].isOutputFolder())
+ // classFoldersAndJars[j] = null; // can ignore output
+ // folder since
+ // project was not structurally changed
+ // else
+ // canSkip = false;
+ // }
+ if (canSkip)
+ continue nextProject; // project has no structural
+ // changes in its
+ // output folders
+ }
+ notifier.subTask(Util.bind("build.readingDelta", p.getName())); //$NON-NLS-1$
+ delta = getDelta(p);
+ if (delta != null) {
+ if (delta.getKind() != IResourceDelta.NO_CHANGE) {
+ if (DEBUG)
+ System.out
+ .println("Found binary delta for: " + p.getName()); //$NON-NLS-1$
+ deltas.put(p, delta);
+ }
+ } else {
+ if (DEBUG)
+ System.out.println("Missing delta for: " + p.getName()); //$NON-NLS-1$
+ notifier.subTask(""); //$NON-NLS-1$
+ return null;
+ }
+ }
+ }
+ notifier.subTask(""); //$NON-NLS-1$
+ return deltas;
+ }
+
+ private State getLastState(IProject project) {
+ return (State) JavaModelManager.getJavaModelManager()
+ .getLastBuiltState(project, notifier.monitor);
+ }
+
+ /*
+ * Return the list of projects for which it requires a resource delta. This
+ * builder's project is implicitly included and need not be specified.
+ * Builders must re-specify the list of interesting projects every time they
+ * are run as this is not carried forward beyond the next build. Missing
+ * projects should be specified but will be ignored until they are added to
+ * the workspace.
+ */
+ private IProject[] getRequiredProjects(boolean includeBinaryPrerequisites) {
+ if (javaProject == null || workspaceRoot == null)
+ return new IProject[0];
+ ArrayList projects = new ArrayList();
+ try {
+ IClasspathEntry[] entries = javaProject.getExpandedClasspath(true);
+ for (int i = 0, l = entries.length; i < l; i++) {
+ IClasspathEntry entry = entries[i];
+ IPath path = entry.getPath();
+ IProject p = null;
+ switch (entry.getEntryKind()) {
+ case IClasspathEntry.CPE_PROJECT:
+ p = workspaceRoot.getProject(path.lastSegment()); // missing
+ // projects are
+ // considered too
+ break;
+ case IClasspathEntry.CPE_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 (JavaModelException e) {
+ return new IProject[0];
+ }
+ IProject[] result = new IProject[projects.size()];
+ projects.toArray(result);
+ return result;
+ }
+
+ // private boolean hasClasspathChanged() {
+ // ClasspathMultiDirectory[] newSourceLocations =
+ // nameEnvironment.sourceLocations;
+ // ClasspathMultiDirectory[] oldSourceLocations = lastState.sourceLocations;
+ // int newLength = newSourceLocations.length;
+ // int oldLength = oldSourceLocations.length;
+ // int n, o;
+ // for (n = o = 0; n < newLength && o < oldLength; n++, o++) {
+ // if (newSourceLocations[n].equals(oldSourceLocations[o]))
+ // continue; // checks source & output folders
+ // try {
+ // if (newSourceLocations[n].sourceFolder.members().length == 0) { // added
+ // // new
+ // // empty
+ // // source
+ // // folder
+ // o--;
+ // continue;
+ // }
+ // } catch (CoreException ignore) {
+ // }
+ // if (DEBUG)
+ // System.out.println(newSourceLocations[n] + " != "
+ // + oldSourceLocations[o]); //$NON-NLS-1$
+ // return true;
+ // }
+ // while (n < newLength) {
+ // try {
+ // if (newSourceLocations[n].sourceFolder.members().length == 0) { // added
+ // // new
+ // // empty
+ // // source
+ // // folder
+ // n++;
+ // continue;
+ // }
+ // } catch (CoreException ignore) {
+ // }
+ // if (DEBUG)
+ // System.out.println("Added non-empty source folder"); //$NON-NLS-1$
+ // return true;
+ // }
+ // if (o < oldLength) {
+ // if (DEBUG)
+ // System.out.println("Removed source folder"); //$NON-NLS-1$
+ // return true;
+ // }
+ // // ClasspathLocation[] newBinaryLocations =
+ // // nameEnvironment.binaryLocations;
+ // // ClasspathLocation[] oldBinaryLocations = lastState.binaryLocations;
+ // // newLength = newBinaryLocations.length;
+ // // oldLength = oldBinaryLocations.length;
+ // // for (n = o = 0; n < newLength && o < oldLength; n++, o++) {
+ // // if (newBinaryLocations[n].equals(oldBinaryLocations[o])) continue;
+ // // if (DEBUG)
+ // // System.out.println(newBinaryLocations[n] + " != " +
+ // // oldBinaryLocations[o]); //$NON-NLS-1$
+ // // return true;
+ // // }
+ // // if (n < newLength || o < oldLength) {
+ // // if (DEBUG)
+ // // System.out.println("Number of binary folders/jar files has changed");
+ // // //$NON-NLS-1$
+ // // return true;
+ // // }
+ // return false;
+ // }
+ private boolean hasStructuralDelta() {
+ // handle case when currentProject has only .class file folders and/or
+ // jar
+ // files... no source/output folders
+ IResourceDelta delta = getDelta(currentProject);
+ if (delta != null && delta.getKind() != IResourceDelta.NO_CHANGE) {
+ // ClasspathLocation[] classFoldersAndJars = (ClasspathLocation[])
+ // binaryLocationsPerProject.get(currentProject);
+ // if (classFoldersAndJars != null) {
+ // for (int i = 0, l = classFoldersAndJars.length; i < l; i++) {
+ // ClasspathLocation classFolderOrJar = classFoldersAndJars[i]; //
+ // either
+ // a .class file folder or a zip/jar file
+ // if (classFolderOrJar != null) {
+ // IPath p = classFolderOrJar.getProjectRelativePath();
+ // if (p != null) {
+ // IResourceDelta binaryDelta = delta.findMember(p);
+ // if (binaryDelta != null && binaryDelta.getKind() !=
+ // IResourceDelta.NO_CHANGE)
+ // return true;
+ // }
+ // }
+ // }
+ // }
+ }
+ return false;
+ }
+
+ private void initializeBuilder() throws CoreException {
+ this.javaProject = (JavaProject) JavaCore.create(currentProject);
+ this.workspaceRoot = currentProject.getWorkspace().getRoot();
+ // Flush the existing external files cache if this is the beginning of a
+ // build cycle
+ String projectName = currentProject.getName();
+ if (builtProjects == null || builtProjects.contains(projectName)) {
+ JavaModel.flushExternalFileCache();
+ builtProjects = new ArrayList();
+ }
+ builtProjects.add(projectName);
+ this.binaryLocationsPerProject = new SimpleLookupTable(3);
+ this.nameEnvironment = new NameEnvironment(workspaceRoot, javaProject,
+ binaryLocationsPerProject);
+ String filterSequence = javaProject.getOption(
+ JavaCore.CORE_JAVA_BUILD_RESOURCE_COPY_FILTER, true);
+ char[][] filters = filterSequence != null
+ && filterSequence.length() > 0 ? CharOperation.splitAndTrimOn(
+ ',', filterSequence.toCharArray()) : null;
+ if (filters == null) {
+ this.extraResourceFileFilters = null;
+ this.extraResourceFolderFilters = null;
+ } else {
+ int fileCount = 0, folderCount = 0;
+ for (int i = 0, l = filters.length; i < l; i++) {
+ char[] f = filters[i];
+ if (f.length == 0)
+ continue;
+ if (f[f.length - 1] == '/')
+ folderCount++;
+ else
+ fileCount++;
+ }
+ this.extraResourceFileFilters = new char[fileCount][];
+ this.extraResourceFolderFilters = new String[folderCount];
+ for (int i = 0, l = filters.length; i < l; i++) {
+ char[] f = filters[i];
+ if (f.length == 0)
+ continue;
+ if (f[f.length - 1] == '/')
+ extraResourceFolderFilters[--folderCount] = new String(
+ CharOperation.subarray(f, 0, f.length - 1));
+ else
+ extraResourceFileFilters[--fileCount] = f;
+ }
+ }
+ }
+
+ private boolean isClasspathBroken(IClasspathEntry[] classpath, IProject p)
+ throws CoreException {
+ if (classpath == JavaProject.INVALID_CLASSPATH) // the .classpath file
+ // could not be read
+ return true;
+ IMarker[] markers = p.findMarkers(
+ IJavaModelMarker.BUILDPATH_PROBLEM_MARKER, false,
+ IResource.DEPTH_ZERO);
+ for (int i = 0, l = markers.length; i < l; i++)
+ if (((Integer) markers[i].getAttribute(IMarker.SEVERITY))
+ .intValue() == IMarker.SEVERITY_ERROR)
+ return true;
+ return false;
+ }
+
+ private boolean isWorthBuilding() throws CoreException {
+ boolean abortBuilds = JavaCore.ABORT.equals(javaProject.getOption(
+ JavaCore.CORE_JAVA_BUILD_INVALID_CLASSPATH, true));
+ if (!abortBuilds)
+ return true;
+ // Abort build only if there are classpath errors
+ // if (isClasspathBroken(javaProject.getRawClasspath(), currentProject))
+ // {
+ // if (DEBUG)
+ // System.out.println("Aborted build because project has classpath
+ // errors
+ // (incomplete or involved in cycle)"); //$NON-NLS-1$
+ //
+ // JavaModelManager.getJavaModelManager().deltaProcessor.addForRefresh(javaProject);
+ //
+ // removeProblemsAndTasksFor(currentProject); // remove all compilation
+ // problems
+ //
+ // IMarker marker =
+ // currentProject.createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
+ // marker.setAttribute(IMarker.MESSAGE,
+ // ProjectPrefUtil.bind("build.abortDueToClasspathProblems"));
+ // //$NON-NLS-1$
+ // marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
+ // return false;
+ // }
+ // make sure all prereq projects have valid build states... only when
+ // aborting builds since projects in cycles do not have build states
+ // except for projects involved in a 'warning' cycle (see below)
+ IProject[] requiredProjects = getRequiredProjects(false);
+ next: for (int i = 0, l = requiredProjects.length; i < l; i++) {
+ IProject p = requiredProjects[i];
+ if (getLastState(p) == null) {
+ // The prereq project has no build state: if this prereq project
+ // has a
+ // 'warning' cycle marker then allow build (see bug id 23357)
+ JavaProject prereq = (JavaProject) JavaCore.create(p);
+ if (prereq.hasCycleMarker()
+ && JavaCore.WARNING.equals(javaProject.getOption(
+ JavaCore.CORE_CIRCULAR_CLASSPATH, true)))
+ continue;
+ if (DEBUG)
+ System.out.println("Aborted build because prereq project "
+ + p.getName() //$NON-NLS-1$
+ + " was not built"); //$NON-NLS-1$
+ removeProblemsAndTasksFor(currentProject); // make this the
+ // only
+ // problem for this project
+ IMarker marker = currentProject
+ .createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
+ marker
+ .setAttribute(
+ IMarker.MESSAGE,
+ isClasspathBroken(prereq.getRawClasspath(), p) ? Util
+ .bind(
+ "build.prereqProjectHasClasspathProblems", p.getName()) //$NON-NLS-1$
+ : Util
+ .bind(
+ "build.prereqProjectMustBeRebuilt", p.getName())); //$NON-NLS-1$
+ marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /*
+ * Instruct the build manager that this project is involved in a cycle and
+ * needs to propagate structural changes to the other projects in the cycle.
+ */
+ void mustPropagateStructuralChanges() {
+ HashSet cycleParticipants = new HashSet(3);
+ javaProject.updateCycleParticipants(null, new ArrayList(),
+ cycleParticipants, workspaceRoot, new HashSet(3));
+ IPath currentPath = javaProject.getPath();
+ Iterator i = cycleParticipants.iterator();
+ while (i.hasNext()) {
+ IPath participantPath = (IPath) i.next();
+ if (participantPath != currentPath) {
+ IProject project = this.workspaceRoot
+ .getProject(participantPath.segment(0));
+ if (hasBeenBuilt(project)) {
+ if (DEBUG)
+ System.out
+ .println("Requesting another build iteration since cycle participant "
+ + project.getName() //$NON-NLS-1$
+ + " has not yet seen some structural changes"); //$NON-NLS-1$
+ needRebuild();
+ return;
+ }
+ }
+ }
+ }
+
+ private void recordNewState(State state) {
+ Object[] keyTable = binaryLocationsPerProject.keyTable;
+ for (int i = 0, l = keyTable.length; i < l; i++) {
+ IProject prereqProject = (IProject) keyTable[i];
+ if (prereqProject != null && prereqProject != currentProject)
+ state.recordStructuralDependency(prereqProject,
+ getLastState(prereqProject));
+ }
+ if (DEBUG)
+ System.out.println("Recording new state : " + state); //$NON-NLS-1$
+ // state.dump();
+ JavaModelManager.getJavaModelManager().setLastBuiltState(
+ currentProject, state);
+ }
+
+ /**
+ * String representation for debugging purposes
+ */
+ public String toString() {
+ return currentProject == null ? "JavaBuilder for unknown project" //$NON-NLS-1$
+ : "JavaBuilder for " + currentProject.getName(); //$NON-NLS-1$
+ }
}