1 /*******************************************************************************
2 * Copyright (c) 2000, 2003 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package net.sourceforge.phpdt.internal.core.builder;
12 import java.io.DataInputStream;
13 import java.io.DataOutputStream;
14 import java.io.IOException;
15 import java.util.ArrayList;
16 import java.util.Date;
17 import java.util.HashSet;
18 import java.util.Iterator;
21 import net.sourceforge.phpdt.core.IClasspathEntry;
22 import net.sourceforge.phpdt.core.IJavaModelMarker;
23 import net.sourceforge.phpdt.core.JavaCore;
24 import net.sourceforge.phpdt.core.JavaModelException;
25 import net.sourceforge.phpdt.core.compiler.CharOperation;
26 import net.sourceforge.phpdt.internal.core.JavaModel;
27 import net.sourceforge.phpdt.internal.core.JavaModelManager;
28 import net.sourceforge.phpdt.internal.core.JavaProject;
29 import net.sourceforge.phpdt.internal.core.util.SimpleLookupTable;
30 import net.sourceforge.phpdt.internal.core.util.Util;
31 import net.sourceforge.phpdt.internal.ui.util.PHPFileUtil;
32 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
33 import net.sourceforge.phpeclipse.builder.IdentifierIndexManager;
35 import org.eclipse.core.resources.IFile;
36 import org.eclipse.core.resources.IMarker;
37 import org.eclipse.core.resources.IProject;
38 import org.eclipse.core.resources.IResource;
39 import org.eclipse.core.resources.IResourceChangeEvent;
40 import org.eclipse.core.resources.IResourceDelta;
41 import org.eclipse.core.resources.IResourceVisitor;
42 import org.eclipse.core.resources.IWorkspaceRoot;
43 import org.eclipse.core.resources.IncrementalProjectBuilder;
44 import org.eclipse.core.runtime.CoreException;
45 import org.eclipse.core.runtime.IPath;
46 import org.eclipse.core.runtime.IProgressMonitor;
47 import org.eclipse.core.runtime.OperationCanceledException;
49 public class PHPBuilder extends IncrementalProjectBuilder {
50 IProject currentProject;
51 JavaProject javaProject;
52 IWorkspaceRoot workspaceRoot;
53 NameEnvironment nameEnvironment;
54 SimpleLookupTable binaryLocationsPerProject; // maps a project to its binary
55 // resources (output folders,
56 // class folders, zip/jar files)
58 BuildNotifier notifier;
59 char[][] extraResourceFileFilters;
60 String[] extraResourceFolderFilters;
61 public static final String CLASS_EXTENSION = "class"; //$NON-NLS-1$
62 public static boolean DEBUG = false;
64 * A list of project names that have been built. This list is used to reset
65 * the JavaModel.existingExternalFiles cache when a build cycle begins so
66 * that deleted external jars are discovered.
68 static ArrayList builtProjects = null;
69 public static IMarker[] getProblemsFor(IResource resource) {
71 if (resource != null && resource.exists())
72 return resource.findMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER,
73 false, IResource.DEPTH_INFINITE);
74 } catch (CoreException e) {
75 } // assume there are no problems
76 return new IMarker[0];
78 public static IMarker[] getTasksFor(IResource resource) {
80 if (resource != null && resource.exists())
81 return resource.findMarkers(IJavaModelMarker.TASK_MARKER, false,
82 IResource.DEPTH_INFINITE);
83 } catch (CoreException e) {
84 } // assume there are no tasks
85 return new IMarker[0];
87 public static void finishedBuilding(IResourceChangeEvent event) {
88 BuildNotifier.resetProblemCounters();
91 * Hook allowing to initialize some static state before a complete build iteration.
92 * This hook is invoked during PRE_AUTO_BUILD notification
94 public static void buildStarting() {
96 // TODO (philippe) is it still needed?
100 * Hook allowing to reset some static state after a complete build iteration.
101 * This hook is invoked during POST_AUTO_BUILD notification
103 public static void buildFinished() {
104 BuildNotifier.resetProblemCounters();
106 public static void removeProblemsFor(IResource resource) {
108 if (resource != null && resource.exists())
109 resource.deleteMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER,
110 false, IResource.DEPTH_INFINITE);
111 } catch (CoreException e) {
112 } // assume there were no problems
114 public static void removeTasksFor(IResource resource) {
116 if (resource != null && resource.exists())
117 resource.deleteMarkers(IJavaModelMarker.TASK_MARKER, false,
118 IResource.DEPTH_INFINITE);
119 } catch (CoreException e) {
120 } // assume there were no problems
122 public static void removeProblemsAndTasksFor(IResource resource) {
124 if (resource != null && resource.exists()) {
125 resource.deleteMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER,
126 false, IResource.DEPTH_INFINITE);
127 resource.deleteMarkers(IJavaModelMarker.TASK_MARKER, false,
128 IResource.DEPTH_INFINITE);
130 } catch (CoreException e) {
131 } // assume there were no problems
133 public static State readState(IProject project, DataInputStream in)
135 return State.read(project, in);
137 public static void writeState(Object state, DataOutputStream out)
139 ((State) state).write(out);
141 public PHPBuilder() {
143 protected IProject[] build(int kind, Map ignored, IProgressMonitor monitor)
144 throws CoreException {
145 this.currentProject = getProject();
146 if (currentProject == null || !currentProject.isAccessible())
147 return new IProject[0];
149 System.out.println("\nStarting build of " + currentProject.getName() //$NON-NLS-1$
150 + " @ " + new Date(System.currentTimeMillis())); //$NON-NLS-1$
151 this.notifier = new BuildNotifier(monitor, currentProject);
155 notifier.checkCancel();
157 if (isWorthBuilding()) {
158 if (kind == FULL_BUILD) {
159 processFullPHPIndex(currentProject, monitor);
162 if ((this.lastState = getLastState(currentProject)) == null) {
165 .println("Performing full build since last saved state was not found"); //$NON-NLS-1$
166 processFullPHPIndex(currentProject, monitor);
168 // } else if (hasClasspathChanged()) {
169 // // if the output location changes, do not delete the binary files
170 // // from old location
171 // // the user may be trying something
173 } else if (nameEnvironment.sourceLocations.length > 0) {
174 // if there is no source to compile & no classpath changes then we
176 SimpleLookupTable deltas = findDeltas();
179 else if (deltas.elementSize > 0)
182 System.out.println("Nothing to build since deltas were empty"); //$NON-NLS-1$
184 if (hasStructuralDelta()) { // double check that a jar file didn't
185 // get replaced in a binary project
186 processFullPHPIndex(currentProject, monitor);
191 .println("Nothing to build since there are no source folders and no deltas"); //$NON-NLS-1$
192 lastState.tagAsNoopBuild();
198 } catch (CoreException e) {
199 Util.log(e, "JavaBuilder handling CoreException"); //$NON-NLS-1$
200 IMarker marker = currentProject
201 .createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
202 marker.setAttribute(IMarker.MESSAGE, Util.bind(
203 "build.inconsistentProject", e.getLocalizedMessage())); //$NON-NLS-1$
204 marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
205 } catch (ImageBuilderInternalException e) {
206 Util.log(e.getThrowable(),
207 "JavaBuilder handling ImageBuilderInternalException"); //$NON-NLS-1$
208 IMarker marker = currentProject
209 .createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
210 marker.setAttribute(IMarker.MESSAGE, Util.bind(
211 "build.inconsistentProject", e.coreException.getLocalizedMessage())); //$NON-NLS-1$
212 marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
213 } catch (MissingClassFileException e) {
214 // do not log this exception since its thrown to handle aborted compiles
215 // because of missing class files
217 System.out.println(Util.bind("build.incompleteClassPath",
218 e.missingClassFile)); //$NON-NLS-1$
219 IMarker marker = currentProject
220 .createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
221 marker.setAttribute(IMarker.MESSAGE, Util.bind(
222 "build.incompleteClassPath", e.missingClassFile)); //$NON-NLS-1$
223 marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
224 } catch (MissingSourceFileException e) {
225 // do not log this exception since its thrown to handle aborted compiles
226 // because of missing source files
228 System.out.println(Util.bind("build.missingSourceFile",
229 e.missingSourceFile)); //$NON-NLS-1$
230 removeProblemsAndTasksFor(currentProject); // make this the only problem
232 IMarker marker = currentProject
233 .createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
234 marker.setAttribute(IMarker.MESSAGE, Util.bind("build.missingSourceFile",
235 e.missingSourceFile)); //$NON-NLS-1$
236 marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
237 } catch (Exception e) {
241 // If the build failed, clear the previously built state, forcing a
242 // full build next time.
247 IProject[] requiredProjects = getRequiredProjects(true);
249 System.out.println("Finished build of " + currentProject.getName() //$NON-NLS-1$
250 + " @ " + new Date(System.currentTimeMillis())); //$NON-NLS-1$
251 return requiredProjects;
254 * Performs a <code>FULL_BUILD</code> by visiting all nodes in the resource
255 * tree under the specified project.
259 private void processFullPHPIndex(final IProject iProject,
260 final IProgressMonitor monitor) {
261 final IdentifierIndexManager indexManager = PHPeclipsePlugin.getDefault()
262 .getIndexManager(iProject);
263 // Create resource visitor logic
264 IResourceVisitor myVisitor = new IResourceVisitor() {
265 public boolean visit(IResource resource) throws CoreException {
266 if (resource.getType() == IResource.FILE) {
267 if (monitor.isCanceled()) {
268 throw new OperationCanceledException();
270 if ((resource.getFileExtension() != null)
271 && PHPFileUtil.isPHPFile((IFile) resource)) {
273 monitor.subTask("Parsing: " + resource.getFullPath());
274 // update indexfile for the project:
275 // PHPProject nature = (PHPProject) iProject
276 // .getNature(PHPeclipsePlugin.PHP_NATURE_ID);
277 indexManager.addFile((IFile) resource);
283 // Process the project using the visitor just created
285 // if (iProject.hasNature(PHPeclipsePlugin.PHP_NATURE_ID)) {
286 // thePHPProject = new PHPProject();
287 // thePHPProject.setProject(iProject);
289 indexManager.initialize();
290 iProject.accept(myVisitor);
291 indexManager.writeFile();
292 } catch (CoreException e) {
296 private void buildAll() {
297 notifier.checkCancel();
298 notifier.subTask(Util.bind("build.preparingBuild")); //$NON-NLS-1$
299 if (DEBUG && lastState != null)
300 System.out.println("Clearing last state : " + lastState); //$NON-NLS-1$
302 BatchImageBuilder imageBuilder = new BatchImageBuilder(this);
303 imageBuilder.build();
304 recordNewState(imageBuilder.newState);
306 private void buildDeltas(SimpleLookupTable deltas) {
307 notifier.checkCancel();
308 notifier.subTask(Util.bind("build.preparingBuild")); //$NON-NLS-1$
309 if (DEBUG && lastState != null)
310 System.out.println("Clearing last state : " + lastState); //$NON-NLS-1$
311 clearLastState(); // clear the previously built state so if the build
312 // fails, a full build will occur next time
313 IncrementalImageBuilder imageBuilder = new IncrementalImageBuilder(this);
314 if (imageBuilder.build(deltas))
315 recordNewState(imageBuilder.newState);
317 processFullPHPIndex(currentProject, notifier.monitor);
321 private void cleanup() {
322 this.nameEnvironment = null;
323 this.binaryLocationsPerProject = null;
324 this.lastState = null;
325 this.notifier = null;
326 this.extraResourceFileFilters = null;
327 this.extraResourceFolderFilters = null;
329 private void clearLastState() {
330 JavaModelManager.getJavaModelManager().setLastBuiltState(currentProject,
333 boolean filterExtraResource(IResource resource) {
334 if (extraResourceFileFilters != null) {
335 char[] name = resource.getName().toCharArray();
336 for (int i = 0, l = extraResourceFileFilters.length; i < l; i++)
337 if (CharOperation.match(extraResourceFileFilters[i], name, true))
340 if (extraResourceFolderFilters != null) {
341 IPath path = resource.getProjectRelativePath();
342 String pathName = path.toString();
343 int count = path.segmentCount();
344 if (resource.getType() == IResource.FILE)
346 for (int i = 0, l = extraResourceFolderFilters.length; i < l; i++)
347 if (pathName.indexOf(extraResourceFolderFilters[i]) != -1)
348 for (int j = 0; j < count; j++)
349 if (extraResourceFolderFilters[i].equals(path.segment(j)))
354 private SimpleLookupTable findDeltas() {
355 notifier.subTask(Util.bind("build.readingDelta", currentProject.getName())); //$NON-NLS-1$
356 IResourceDelta delta = getDelta(currentProject);
357 SimpleLookupTable deltas = new SimpleLookupTable(3);
359 if (delta.getKind() != IResourceDelta.NO_CHANGE) {
361 System.out.println("Found source delta for: "
362 + currentProject.getName()); //$NON-NLS-1$
363 deltas.put(currentProject, delta);
367 System.out.println("Missing delta for: " + currentProject.getName()); //$NON-NLS-1$
368 notifier.subTask(""); //$NON-NLS-1$
371 Object[] keyTable = binaryLocationsPerProject.keyTable;
372 Object[] valueTable = binaryLocationsPerProject.valueTable;
373 nextProject : for (int i = 0, l = keyTable.length; i < l; i++) {
374 IProject p = (IProject) keyTable[i];
375 if (p != null && p != currentProject) {
376 State s = getLastState(p);
377 if (!lastState.wasStructurallyChanged(p, s)) { // see if we can skip
379 if (s.wasNoopBuild())
380 continue nextProject; // project has no source folders and can be
382 // ClasspathLocation[] classFoldersAndJars = (ClasspathLocation[])
384 boolean canSkip = true;
385 // for (int j = 0, m = classFoldersAndJars.length; j < m; j++) {
386 // if (classFoldersAndJars[j].isOutputFolder())
387 // classFoldersAndJars[j] = null; // can ignore output folder since
388 // project was not structurally changed
393 continue nextProject; // project has no structural changes in its
396 notifier.subTask(Util.bind("build.readingDelta", p.getName())); //$NON-NLS-1$
399 if (delta.getKind() != IResourceDelta.NO_CHANGE) {
401 System.out.println("Found binary delta for: " + p.getName()); //$NON-NLS-1$
402 deltas.put(p, delta);
406 System.out.println("Missing delta for: " + p.getName()); //$NON-NLS-1$
407 notifier.subTask(""); //$NON-NLS-1$
412 notifier.subTask(""); //$NON-NLS-1$
415 private State getLastState(IProject project) {
416 return (State) JavaModelManager.getJavaModelManager().getLastBuiltState(
417 project, notifier.monitor);
420 * Return the list of projects for which it requires a resource delta. This
421 * builder's project is implicitly included and need not be specified.
422 * Builders must re-specify the list of interesting projects every time they
423 * are run as this is not carried forward beyond the next build. Missing
424 * projects should be specified but will be ignored until they are added to
427 private IProject[] getRequiredProjects(boolean includeBinaryPrerequisites) {
428 if (javaProject == null || workspaceRoot == null)
429 return new IProject[0];
430 ArrayList projects = new ArrayList();
432 IClasspathEntry[] entries = javaProject.getExpandedClasspath(true);
433 for (int i = 0, l = entries.length; i < l; i++) {
434 IClasspathEntry entry = entries[i];
435 IPath path = entry.getPath();
437 switch (entry.getEntryKind()) {
438 case IClasspathEntry.CPE_PROJECT :
439 p = workspaceRoot.getProject(path.lastSegment()); // missing
443 case IClasspathEntry.CPE_LIBRARY :
444 if (includeBinaryPrerequisites && path.segmentCount() > 1) {
445 // some binary resources on the class path can come from projects
446 // that are not included in the project references
447 IResource resource = workspaceRoot.findMember(path.segment(0));
448 if (resource instanceof IProject)
449 p = (IProject) resource;
452 if (p != null && !projects.contains(p))
455 } catch (JavaModelException e) {
456 return new IProject[0];
458 IProject[] result = new IProject[projects.size()];
459 projects.toArray(result);
462 // private boolean hasClasspathChanged() {
463 // ClasspathMultiDirectory[] newSourceLocations = nameEnvironment.sourceLocations;
464 // ClasspathMultiDirectory[] oldSourceLocations = lastState.sourceLocations;
465 // int newLength = newSourceLocations.length;
466 // int oldLength = oldSourceLocations.length;
468 // for (n = o = 0; n < newLength && o < oldLength; n++, o++) {
469 // if (newSourceLocations[n].equals(oldSourceLocations[o]))
470 // continue; // checks source & output folders
472 // if (newSourceLocations[n].sourceFolder.members().length == 0) { // added
480 // } catch (CoreException ignore) {
483 // System.out.println(newSourceLocations[n] + " != "
484 // + oldSourceLocations[o]); //$NON-NLS-1$
487 // while (n < newLength) {
489 // if (newSourceLocations[n].sourceFolder.members().length == 0) { // added
497 // } catch (CoreException ignore) {
500 // System.out.println("Added non-empty source folder"); //$NON-NLS-1$
503 // if (o < oldLength) {
505 // System.out.println("Removed source folder"); //$NON-NLS-1$
508 // // ClasspathLocation[] newBinaryLocations =
509 // // nameEnvironment.binaryLocations;
510 // // ClasspathLocation[] oldBinaryLocations = lastState.binaryLocations;
511 // // newLength = newBinaryLocations.length;
512 // // oldLength = oldBinaryLocations.length;
513 // // for (n = o = 0; n < newLength && o < oldLength; n++, o++) {
514 // // if (newBinaryLocations[n].equals(oldBinaryLocations[o])) continue;
516 // // System.out.println(newBinaryLocations[n] + " != " +
517 // // oldBinaryLocations[o]); //$NON-NLS-1$
520 // // if (n < newLength || o < oldLength) {
522 // // System.out.println("Number of binary folders/jar files has changed");
528 private boolean hasStructuralDelta() {
529 // handle case when currentProject has only .class file folders and/or jar
530 // files... no source/output folders
531 IResourceDelta delta = getDelta(currentProject);
532 if (delta != null && delta.getKind() != IResourceDelta.NO_CHANGE) {
533 // ClasspathLocation[] classFoldersAndJars = (ClasspathLocation[])
534 // binaryLocationsPerProject.get(currentProject);
535 // if (classFoldersAndJars != null) {
536 // for (int i = 0, l = classFoldersAndJars.length; i < l; i++) {
537 // ClasspathLocation classFolderOrJar = classFoldersAndJars[i]; // either
538 // a .class file folder or a zip/jar file
539 // if (classFolderOrJar != null) {
540 // IPath p = classFolderOrJar.getProjectRelativePath();
542 // IResourceDelta binaryDelta = delta.findMember(p);
543 // if (binaryDelta != null && binaryDelta.getKind() !=
544 // IResourceDelta.NO_CHANGE)
553 private void initializeBuilder() throws CoreException {
554 this.javaProject = (JavaProject) JavaCore.create(currentProject);
555 this.workspaceRoot = currentProject.getWorkspace().getRoot();
556 // Flush the existing external files cache if this is the beginning of a
558 String projectName = currentProject.getName();
559 if (builtProjects == null || builtProjects.contains(projectName)) {
560 JavaModel.flushExternalFileCache();
561 builtProjects = new ArrayList();
563 builtProjects.add(projectName);
564 this.binaryLocationsPerProject = new SimpleLookupTable(3);
565 this.nameEnvironment = new NameEnvironment(workspaceRoot, javaProject,
566 binaryLocationsPerProject);
567 String filterSequence = javaProject.getOption(
568 JavaCore.CORE_JAVA_BUILD_RESOURCE_COPY_FILTER, true);
569 char[][] filters = filterSequence != null && filterSequence.length() > 0
570 ? CharOperation.splitAndTrimOn(',', filterSequence.toCharArray())
572 if (filters == null) {
573 this.extraResourceFileFilters = null;
574 this.extraResourceFolderFilters = null;
576 int fileCount = 0, folderCount = 0;
577 for (int i = 0, l = filters.length; i < l; i++) {
578 char[] f = filters[i];
581 if (f[f.length - 1] == '/')
586 this.extraResourceFileFilters = new char[fileCount][];
587 this.extraResourceFolderFilters = new String[folderCount];
588 for (int i = 0, l = filters.length; i < l; i++) {
589 char[] f = filters[i];
592 if (f[f.length - 1] == '/')
593 extraResourceFolderFilters[--folderCount] = new String(CharOperation
594 .subarray(f, 0, f.length - 1));
596 extraResourceFileFilters[--fileCount] = f;
600 private boolean isClasspathBroken(IClasspathEntry[] classpath, IProject p)
601 throws CoreException {
602 if (classpath == JavaProject.INVALID_CLASSPATH) // the .classpath file
605 IMarker[] markers = p.findMarkers(
606 IJavaModelMarker.BUILDPATH_PROBLEM_MARKER, false, IResource.DEPTH_ZERO);
607 for (int i = 0, l = markers.length; i < l; i++)
608 if (((Integer) markers[i].getAttribute(IMarker.SEVERITY)).intValue() == IMarker.SEVERITY_ERROR)
612 private boolean isWorthBuilding() throws CoreException {
613 boolean abortBuilds = JavaCore.ABORT.equals(javaProject.getOption(
614 JavaCore.CORE_JAVA_BUILD_INVALID_CLASSPATH, true));
617 // Abort build only if there are classpath errors
618 // if (isClasspathBroken(javaProject.getRawClasspath(), currentProject)) {
620 // System.out.println("Aborted build because project has classpath errors
621 // (incomplete or involved in cycle)"); //$NON-NLS-1$
623 // JavaModelManager.getJavaModelManager().deltaProcessor.addForRefresh(javaProject);
625 // removeProblemsAndTasksFor(currentProject); // remove all compilation
629 // currentProject.createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
630 // marker.setAttribute(IMarker.MESSAGE,
631 // Util.bind("build.abortDueToClasspathProblems")); //$NON-NLS-1$
632 // marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
635 // make sure all prereq projects have valid build states... only when
636 // aborting builds since projects in cycles do not have build states
637 // except for projects involved in a 'warning' cycle (see below)
638 IProject[] requiredProjects = getRequiredProjects(false);
639 next : for (int i = 0, l = requiredProjects.length; i < l; i++) {
640 IProject p = requiredProjects[i];
641 if (getLastState(p) == null) {
642 // The prereq project has no build state: if this prereq project has a
643 // 'warning' cycle marker then allow build (see bug id 23357)
644 JavaProject prereq = (JavaProject) JavaCore.create(p);
645 if (prereq.hasCycleMarker()
646 && JavaCore.WARNING.equals(javaProject.getOption(
647 JavaCore.CORE_CIRCULAR_CLASSPATH, true)))
650 System.out.println("Aborted build because prereq project "
651 + p.getName() //$NON-NLS-1$
652 + " was not built"); //$NON-NLS-1$
653 removeProblemsAndTasksFor(currentProject); // make this the only
654 // problem for this project
655 IMarker marker = currentProject
656 .createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
657 marker.setAttribute(IMarker.MESSAGE, isClasspathBroken(prereq
658 .getRawClasspath(), p) ? Util.bind(
659 "build.prereqProjectHasClasspathProblems", p.getName()) //$NON-NLS-1$
660 : Util.bind("build.prereqProjectMustBeRebuilt", p.getName())); //$NON-NLS-1$
661 marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
668 * Instruct the build manager that this project is involved in a cycle and
669 * needs to propagate structural changes to the other projects in the cycle.
671 void mustPropagateStructuralChanges() {
672 HashSet cycleParticipants = new HashSet(3);
673 javaProject.updateCycleParticipants(null, new ArrayList(),
674 cycleParticipants, workspaceRoot, new HashSet(3));
675 IPath currentPath = javaProject.getPath();
676 Iterator i = cycleParticipants.iterator();
677 while (i.hasNext()) {
678 IPath participantPath = (IPath) i.next();
679 if (participantPath != currentPath) {
680 IProject project = this.workspaceRoot.getProject(participantPath
682 if (hasBeenBuilt(project)) {
685 .println("Requesting another build iteration since cycle participant "
686 + project.getName() //$NON-NLS-1$
687 + " has not yet seen some structural changes"); //$NON-NLS-1$
694 private void recordNewState(State state) {
695 Object[] keyTable = binaryLocationsPerProject.keyTable;
696 for (int i = 0, l = keyTable.length; i < l; i++) {
697 IProject prereqProject = (IProject) keyTable[i];
698 if (prereqProject != null && prereqProject != currentProject)
699 state.recordStructuralDependency(prereqProject,
700 getLastState(prereqProject));
703 System.out.println("Recording new state : " + state); //$NON-NLS-1$
705 JavaModelManager.getJavaModelManager().setLastBuiltState(currentProject,
709 * String representation for debugging purposes
711 public String toString() {
712 return currentProject == null ? "JavaBuilder for unknown project" //$NON-NLS-1$
713 : "JavaBuilder for " + currentProject.getName(); //$NON-NLS-1$