Lines 11-16
Link Here
|
11 |
* Anton Leherbauer (Wind River) - [305858] Allow Builder to return null rule |
11 |
* Anton Leherbauer (Wind River) - [305858] Allow Builder to return null rule |
12 |
* James Blackburn (Broadcom) - [306822] Provide Context for Builder getRule() |
12 |
* James Blackburn (Broadcom) - [306822] Provide Context for Builder getRule() |
13 |
* Broadcom Corporation - ongoing development |
13 |
* Broadcom Corporation - ongoing development |
|
|
14 |
* Jens Kuebler - [126121] - Initial changes to support parallel build |
15 |
* Morgan Stanley - [126121] Fixing parallel build concurrency issues |
14 |
*******************************************************************************/ |
16 |
*******************************************************************************/ |
15 |
package org.eclipse.core.internal.events; |
17 |
package org.eclipse.core.internal.events; |
16 |
|
18 |
|
Lines 99-108
public class BuildManager implements ICoreConstants, IManager, ILifecycleListene
Link Here
|
99 |
private final Set<IProject> builtProjects = new HashSet<IProject>(); |
101 |
private final Set<IProject> builtProjects = new HashSet<IProject>(); |
100 |
|
102 |
|
101 |
//the following four fields only apply for the lifetime of a single builder invocation. |
103 |
//the following four fields only apply for the lifetime of a single builder invocation. |
102 |
protected InternalBuilder currentBuilder; |
104 |
protected final ThreadLocal<InternalBuilder> currentBuilder = new ThreadLocal<InternalBuilder>(); |
103 |
private DeltaDataTree currentDelta; |
105 |
private final ThreadLocal<DeltaDataTree> currentDelta = new ThreadLocal<DeltaDataTree>(); |
104 |
private ElementTree currentLastBuiltTree; |
106 |
private final ThreadLocal<ElementTree> currentLastBuiltTree = new ThreadLocal<ElementTree>(); |
105 |
private ElementTree currentTree; |
107 |
private final ThreadLocal<ElementTree> currentTree = new ThreadLocal<ElementTree>(); |
106 |
|
108 |
|
107 |
/** |
109 |
/** |
108 |
* Caches the IResourceDelta for a pair of trees |
110 |
* Caches the IResourceDelta for a pair of trees |
Lines 134-151
public class BuildManager implements ICoreConstants, IManager, ILifecycleListene
Link Here
|
134 |
|
136 |
|
135 |
private void basicBuild(int trigger, IncrementalProjectBuilder builder, Map<String, String> args, MultiStatus status, IProgressMonitor monitor) { |
137 |
private void basicBuild(int trigger, IncrementalProjectBuilder builder, Map<String, String> args, MultiStatus status, IProgressMonitor monitor) { |
136 |
try { |
138 |
try { |
137 |
currentBuilder = builder; |
139 |
// flag required for different locking behaviour |
|
|
140 |
boolean notParallel = !(trigger == IncrementalProjectBuilder.PARALLEL_CLEAN_BUILD || trigger == IncrementalProjectBuilder.PARALLEL_FULL_BUILD); |
141 |
|
142 |
// Builder impl may not know about Parallel build types and it is not even interesting on the per project level |
143 |
if (trigger == IncrementalProjectBuilder.PARALLEL_FULL_BUILD) { |
144 |
trigger = IncrementalProjectBuilder.FULL_BUILD; |
145 |
} |
146 |
if (trigger == IncrementalProjectBuilder.PARALLEL_CLEAN_BUILD) { |
147 |
trigger = IncrementalProjectBuilder.CLEAN_BUILD; |
148 |
} |
149 |
|
150 |
currentBuilder.set(builder); |
138 |
//clear any old requests to forget built state |
151 |
//clear any old requests to forget built state |
139 |
currentBuilder.clearLastBuiltStateRequests(); |
152 |
currentBuilder.get().clearLastBuiltStateRequests(); |
140 |
// Figure out want kind of build is needed |
153 |
// Figure out want kind of build is needed |
141 |
boolean clean = trigger == IncrementalProjectBuilder.CLEAN_BUILD; |
154 |
boolean clean = (trigger == IncrementalProjectBuilder.CLEAN_BUILD); |
142 |
currentLastBuiltTree = currentBuilder.getLastBuiltTree(); |
155 |
currentLastBuiltTree.set(currentBuilder.get().getLastBuiltTree()); |
143 |
|
156 |
|
144 |
// Does the build command respond to this trigger? |
157 |
// Does the build command respond to this trigger? |
145 |
boolean isBuilding = builder.getCommand().isBuilding(trigger); |
158 |
boolean isBuilding = builder.getCommand().isBuilding(trigger); |
146 |
|
159 |
|
147 |
// If no tree is available we have to do a full build |
160 |
// If no tree is available we have to do a full build |
148 |
if (!clean && currentLastBuiltTree == null) { |
161 |
if (!clean && currentLastBuiltTree.get() == null) { |
149 |
// Bug 306746 - Don't promote build to FULL_BUILD if builder doesn't AUTO_BUILD |
162 |
// Bug 306746 - Don't promote build to FULL_BUILD if builder doesn't AUTO_BUILD |
150 |
if (trigger == IncrementalProjectBuilder.AUTO_BUILD && !isBuilding) |
163 |
if (trigger == IncrementalProjectBuilder.AUTO_BUILD && !isBuilding) |
151 |
return; |
164 |
return; |
Lines 157-180
public class BuildManager implements ICoreConstants, IManager, ILifecycleListene
Link Here
|
157 |
//don't build if this builder doesn't respond to the trigger |
170 |
//don't build if this builder doesn't respond to the trigger |
158 |
if (!isBuilding) { |
171 |
if (!isBuilding) { |
159 |
if (clean) |
172 |
if (clean) |
160 |
currentBuilder.setLastBuiltTree(null); |
173 |
currentBuilder.get().setLastBuiltTree(null); |
161 |
return; |
174 |
return; |
162 |
} |
175 |
} |
163 |
|
176 |
|
164 |
// For incremental builds, grab a pointer to the current state before computing the delta |
177 |
// For incremental builds, grab a pointer to the current state before computing the delta |
165 |
currentTree = ((trigger == IncrementalProjectBuilder.FULL_BUILD) || clean) ? null : workspace.getElementTree(); |
178 |
currentTree.set(((trigger == IncrementalProjectBuilder.FULL_BUILD) || clean) ? null : workspace.getElementTree()); |
166 |
int depth = -1; |
179 |
int depth = -1; |
167 |
ISchedulingRule rule = null; |
180 |
ISchedulingRule rule = null; |
168 |
try { |
181 |
try { |
169 |
//short-circuit if none of the projects this builder cares about have changed. |
182 |
//short-circuit if none of the projects this builder cares about have changed. |
170 |
if (!needsBuild(currentBuilder, trigger)) { |
183 |
if (!needsBuild(currentBuilder.get(), trigger)) { |
171 |
//use up the progress allocated for this builder |
184 |
//use up the progress allocated for this builder |
172 |
monitor.beginTask("", 1); //$NON-NLS-1$ |
185 |
monitor.beginTask("", 1); //$NON-NLS-1$ |
173 |
monitor.done(); |
186 |
monitor.done(); |
174 |
return; |
187 |
return; |
175 |
} |
188 |
} |
176 |
rule = builder.getRule(trigger, args); |
189 |
rule = builder.getRule(trigger, args); |
177 |
String name = currentBuilder.getLabel(); |
190 |
String name = currentBuilder.get().getLabel(); |
178 |
String message; |
191 |
String message; |
179 |
if (name != null) |
192 |
if (name != null) |
180 |
message = NLS.bind(Messages.events_invoking_2, name, builder.getProject().getFullPath()); |
193 |
message = NLS.bind(Messages.events_invoking_2, name, builder.getProject().getFullPath()); |
Lines 183-230
public class BuildManager implements ICoreConstants, IManager, ILifecycleListene
Link Here
|
183 |
monitor.subTask(message); |
196 |
monitor.subTask(message); |
184 |
hookStartBuild(builder, trigger); |
197 |
hookStartBuild(builder, trigger); |
185 |
// Make the current tree immutable before releasing the WS lock |
198 |
// Make the current tree immutable before releasing the WS lock |
186 |
if (rule != null && currentTree != null) |
199 |
if (rule != null && currentTree.get() != null) |
187 |
workspace.newWorkingTree(); |
200 |
workspace.newWorkingTree(); |
188 |
//release workspace lock while calling builders |
201 |
//release workspace lock while calling builders |
189 |
depth = getWorkManager().beginUnprotected(); |
202 |
if (notParallel) { |
|
|
203 |
depth = getWorkManager().beginUnprotected(); |
204 |
} |
190 |
// Acquire the rule required for running this builder |
205 |
// Acquire the rule required for running this builder |
191 |
if (rule != null) { |
206 |
if (rule != null) { |
192 |
Job.getJobManager().beginRule(rule, monitor); |
207 |
Job.getJobManager().beginRule(rule, monitor); |
193 |
// Now that we've acquired the rule, changes may have been made concurrently, ensure we're pointing at the |
208 |
// Now that we've acquired the rule, changes may have been made concurrently, ensure we're pointing at the |
194 |
// correct currentTree so delta contains concurrent changes made in areas guarded by the scheduling rule |
209 |
// correct currentTree so delta contains concurrent changes made in areas guarded by the scheduling rule |
195 |
if (currentTree != null) |
210 |
if (currentTree.get() != null) |
196 |
currentTree = workspace.getElementTree(); |
211 |
currentTree.set(workspace.getElementTree()); |
197 |
} |
212 |
} |
198 |
//do the build |
213 |
//do the build |
199 |
SafeRunner.run(getSafeRunnable(trigger, args, status, monitor)); |
214 |
SafeRunner.run(getSafeRunnable(trigger, args, status, monitor, currentBuilder.get())); |
200 |
} finally { |
215 |
} finally { |
201 |
// Re-acquire the WS lock, then release the scheduling rule |
216 |
// Re-acquire the WS lock, then release the scheduling rule |
202 |
if (depth >= 0) |
217 |
if (notParallel && depth >= 0) |
203 |
getWorkManager().endUnprotected(depth); |
218 |
getWorkManager().endUnprotected(depth); |
204 |
if (rule != null) |
219 |
if (rule != null) |
205 |
Job.getJobManager().endRule(rule); |
220 |
Job.getJobManager().endRule(rule); |
206 |
// Be sure to clean up after ourselves. |
221 |
// Be sure to clean up after ourselves. |
207 |
if (clean || currentBuilder.wasForgetStateRequested()) { |
222 |
if (clean || currentBuilder.get().wasForgetStateRequested()) { |
208 |
currentBuilder.setLastBuiltTree(null); |
223 |
currentBuilder.get().setLastBuiltTree(null); |
209 |
} else if (currentBuilder.wasRememberStateRequested()) { |
224 |
} else if (currentBuilder.get().wasRememberStateRequested()) { |
210 |
// If remember last build state, and FULL_BUILD |
225 |
// If remember last build state, and FULL_BUILD |
211 |
// last tree must be set to => null for next build |
226 |
// last tree must be set to => null for next build |
212 |
if (trigger == IncrementalProjectBuilder.FULL_BUILD) |
227 |
if (trigger == IncrementalProjectBuilder.FULL_BUILD) |
213 |
currentBuilder.setLastBuiltTree(null); |
228 |
currentBuilder.get().setLastBuiltTree(null); |
214 |
// else don't modify the last built tree |
229 |
// else don't modify the last built tree |
215 |
} else { |
230 |
} else { |
216 |
// remember the current state as the last built state. |
231 |
// remember the current state as the last built state. |
217 |
ElementTree lastTree = workspace.getElementTree(); |
232 |
ElementTree lastTree = workspace.getElementTree(); |
218 |
lastTree.immutable(); |
233 |
// lastTree.immutable(); |
219 |
currentBuilder.setLastBuiltTree(lastTree); |
234 |
currentBuilder.get().setLastBuiltTree(lastTree); |
220 |
} |
235 |
} |
221 |
hookEndBuild(builder); |
236 |
hookEndBuild(builder); |
222 |
} |
237 |
} |
223 |
} finally { |
238 |
} finally { |
224 |
currentBuilder = null; |
239 |
currentBuilder.set(null); |
225 |
currentTree = null; |
240 |
currentTree.set(null); |
226 |
currentLastBuiltTree = null; |
241 |
currentLastBuiltTree.set(null); |
227 |
currentDelta = null; |
242 |
currentDelta.set(null); |
228 |
} |
243 |
} |
229 |
} |
244 |
} |
230 |
|
245 |
|
Lines 234-240
public class BuildManager implements ICoreConstants, IManager, ILifecycleListene
Link Here
|
234 |
checkCanceled(trigger, monitor); |
249 |
checkCanceled(trigger, monitor); |
235 |
BuildCommand command = (BuildCommand) commands[i]; |
250 |
BuildCommand command = (BuildCommand) commands[i]; |
236 |
IProgressMonitor sub = Policy.subMonitorFor(monitor, 1); |
251 |
IProgressMonitor sub = Policy.subMonitorFor(monitor, 1); |
237 |
IncrementalProjectBuilder builder = getBuilder(buildConfiguration, command, i, status, context); |
252 |
IncrementalProjectBuilder builder; |
|
|
253 |
if(IncrementalProjectBuilder.PARALLEL_FULL_BUILD == trigger || IncrementalProjectBuilder.PARALLEL_CLEAN_BUILD == trigger) { |
254 |
builder = getParallelBuilder(buildConfiguration, command, i, status, context); |
255 |
} else { |
256 |
builder = getBuilder(buildConfiguration, command, i, status, context); |
257 |
} |
238 |
if (builder != null) |
258 |
if (builder != null) |
239 |
basicBuild(trigger, builder, command.getArguments(false), status, sub); |
259 |
basicBuild(trigger, builder, command.getArguments(false), status, sub); |
240 |
} |
260 |
} |
Lines 362-387
public class BuildManager implements ICoreConstants, IManager, ILifecycleListene
Link Here
|
362 |
* they are given. |
382 |
* they are given. |
363 |
* @return A status indicating if the build succeeded or failed |
383 |
* @return A status indicating if the build succeeded or failed |
364 |
*/ |
384 |
*/ |
365 |
public IStatus build(IBuildConfiguration[] configs, IBuildConfiguration[] requestedConfigs, int trigger, IProgressMonitor monitor) { |
385 |
public IStatus build(final IBuildConfiguration[] configs, final IBuildConfiguration[] requestedConfigs, final int trigger, final IProgressMonitor monitor) { |
366 |
monitor = Policy.monitorFor(monitor); |
386 |
if (trigger == IncrementalProjectBuilder.PARALLEL_FULL_BUILD || trigger == IncrementalProjectBuilder.PARALLEL_CLEAN_BUILD) { |
367 |
try { |
387 |
|
368 |
monitor.beginTask(Messages.events_building_0, TOTAL_BUILD_WORK); |
388 |
final String buildType = (trigger == IncrementalProjectBuilder.PARALLEL_FULL_BUILD) ? "Parallel full build" : "Parallel clean build"; |
369 |
if (!canRun(trigger)) |
389 |
Job job = new Job(buildType) { |
370 |
return Status.OK_STATUS; |
390 |
|
371 |
try { |
391 |
@Override |
372 |
hookStartBuild(configs, trigger); |
392 |
protected IStatus run(IProgressMonitor monitor) { |
373 |
MultiStatus status = new MultiStatus(ResourcesPlugin.PI_RESOURCES, IResourceStatus.BUILD_FAILED, Messages.events_errors, null); |
393 |
try { |
374 |
basicBuildLoop(configs, requestedConfigs, trigger, status, monitor); |
394 |
IBuildConfiguration[] buildConfigs = requestedConfigs.length > 0 ? requestedConfigs : configs; |
375 |
return status; |
395 |
if (trigger == IncrementalProjectBuilder.PARALLEL_CLEAN_BUILD) { |
376 |
} finally { |
396 |
buildParallel(IncrementalProjectBuilder.PARALLEL_CLEAN_BUILD, monitor, buildConfigs); |
377 |
hookEndBuild(trigger); |
397 |
} |
378 |
} |
398 |
buildParallel(IncrementalProjectBuilder.PARALLEL_FULL_BUILD, monitor, buildConfigs); |
379 |
} finally { |
399 |
} catch (CoreException e) { |
380 |
monitor.done(); |
400 |
e.printStackTrace(); |
381 |
if (trigger == IncrementalProjectBuilder.INCREMENTAL_BUILD || trigger == IncrementalProjectBuilder.FULL_BUILD) |
401 |
return new Status(IStatus.ERROR, ResourcesPlugin.PI_RESOURCES, buildType + " finished with error", e); |
382 |
autoBuildJob.avoidBuild(); |
402 |
} |
383 |
} |
403 |
|
384 |
} |
404 |
return new Status(IStatus.OK, ResourcesPlugin.PI_RESOURCES, buildType + " finished successfully"); |
|
|
405 |
} |
406 |
}; |
407 |
|
408 |
job.setPriority(Job.LONG); |
409 |
job.schedule(); |
410 |
|
411 |
autoBuildJob.avoidBuild(); |
412 |
|
413 |
return Status.OK_STATUS; |
414 |
|
415 |
} else { |
416 |
IProgressMonitor myMonitor = Policy.monitorFor(monitor); |
417 |
try { |
418 |
myMonitor.beginTask(Messages.events_building_0, TOTAL_BUILD_WORK); |
419 |
if (!canRun(trigger)) |
420 |
return Status.OK_STATUS; |
421 |
try { |
422 |
hookStartBuild(configs, trigger); |
423 |
MultiStatus status = new MultiStatus(ResourcesPlugin.PI_RESOURCES, IResourceStatus.BUILD_FAILED, Messages.events_errors, null); |
424 |
basicBuildLoop(configs, requestedConfigs, trigger, status, myMonitor); |
425 |
return status; |
426 |
} finally { |
427 |
hookEndBuild(trigger); |
428 |
} |
429 |
} finally { |
430 |
myMonitor.done(); |
431 |
if (trigger == IncrementalProjectBuilder.INCREMENTAL_BUILD || trigger == IncrementalProjectBuilder.FULL_BUILD) |
432 |
autoBuildJob.avoidBuild(); |
433 |
} |
434 |
} |
435 |
} |
385 |
|
436 |
|
386 |
/** |
437 |
/** |
387 |
* Runs the builder with the given name on the given project config. |
438 |
* Runs the builder with the given name on the given project config. |
Lines 480-492
public class BuildManager implements ICoreConstants, IManager, ILifecycleListene
Link Here
|
480 |
} |
531 |
} |
481 |
|
532 |
|
482 |
private String debugBuilder() { |
533 |
private String debugBuilder() { |
483 |
return currentBuilder == null ? "<no builder>" : currentBuilder.getClass().getName(); //$NON-NLS-1$ |
534 |
return currentBuilder.get() == null ? "<no builder>" : currentBuilder.get().getClass().getName(); //$NON-NLS-1$ |
484 |
} |
535 |
} |
485 |
|
536 |
|
486 |
private String debugProject() { |
537 |
private String debugProject() { |
487 |
if (currentBuilder == null) |
538 |
if (currentBuilder.get() == null) |
488 |
return "<no project>"; //$NON-NLS-1$ |
539 |
return "<no project>"; //$NON-NLS-1$ |
489 |
return currentBuilder.getProject().getFullPath().toString(); |
540 |
return currentBuilder.get().getProject().getFullPath().toString(); |
490 |
} |
541 |
} |
491 |
|
542 |
|
492 |
/** |
543 |
/** |
Lines 498-505
public class BuildManager implements ICoreConstants, IManager, ILifecycleListene
Link Here
|
498 |
switch (trigger) { |
549 |
switch (trigger) { |
499 |
case IncrementalProjectBuilder.FULL_BUILD : |
550 |
case IncrementalProjectBuilder.FULL_BUILD : |
500 |
return "FULL_BUILD"; //$NON-NLS-1$ |
551 |
return "FULL_BUILD"; //$NON-NLS-1$ |
|
|
552 |
case IncrementalProjectBuilder.PARALLEL_FULL_BUILD : |
553 |
return "PARALLEL_FULL_BUILD"; //$NON-NLS-1$ |
501 |
case IncrementalProjectBuilder.CLEAN_BUILD : |
554 |
case IncrementalProjectBuilder.CLEAN_BUILD : |
502 |
return "CLEAN_BUILD"; //$NON-NLS-1$ |
555 |
return "CLEAN_BUILD"; //$NON-NLS-1$ |
|
|
556 |
case IncrementalProjectBuilder.PARALLEL_CLEAN_BUILD : |
557 |
return "PARALLEL_CLEAN_BUILD"; //$NON-NLS-1$ |
503 |
case IncrementalProjectBuilder.AUTO_BUILD : |
558 |
case IncrementalProjectBuilder.AUTO_BUILD : |
504 |
case IncrementalProjectBuilder.INCREMENTAL_BUILD : |
559 |
case IncrementalProjectBuilder.INCREMENTAL_BUILD : |
505 |
default : |
560 |
default : |
Lines 581-598
public class BuildManager implements ICoreConstants, IManager, ILifecycleListene
Link Here
|
581 |
//try to match on builder index, but if not match is found, use the builder name and config name |
636 |
//try to match on builder index, but if not match is found, use the builder name and config name |
582 |
//this is because older workspace versions did not store builder infos in build spec order |
637 |
//this is because older workspace versions did not store builder infos in build spec order |
583 |
BuilderPersistentInfo nameMatch = null; |
638 |
BuilderPersistentInfo nameMatch = null; |
584 |
for (Iterator<BuilderPersistentInfo> it = infos.iterator(); it.hasNext();) { |
639 |
synchronized(infos) { |
585 |
BuilderPersistentInfo info = it.next(); |
640 |
for (Iterator<BuilderPersistentInfo> it = infos.iterator(); it.hasNext();) { |
586 |
// match on name, config name and build spec index if known |
641 |
BuilderPersistentInfo info = it.next(); |
587 |
// Note: the config name may be null for builders that don't support configurations, or old workspaces |
642 |
// match on name, config name and build spec index if known |
588 |
if (info.getBuilderName().equals(builderName) && (info.getConfigName() == null || info.getConfigName().equals(configName))) { |
643 |
// Note: the config name may be null for builders that don't support configurations, or old workspaces |
589 |
//we have found a match on name alone |
644 |
if (info.getBuilderName().equals(builderName) && (info.getConfigName() == null || info.getConfigName().equals(configName))) { |
590 |
if (nameMatch == null) |
645 |
//we have found a match on name alone |
591 |
nameMatch = info; |
646 |
if (nameMatch == null) |
592 |
//see if the index matches |
647 |
nameMatch = info; |
593 |
if (buildSpecIndex == -1 || info.getBuildSpecIndex() == -1 || buildSpecIndex == info.getBuildSpecIndex()) |
648 |
//see if the index matches |
594 |
return info; |
649 |
if (buildSpecIndex == -1 || info.getBuildSpecIndex() == -1 || buildSpecIndex == info.getBuildSpecIndex()) |
595 |
} |
650 |
return info; |
|
|
651 |
} |
652 |
} |
596 |
} |
653 |
} |
597 |
//no exact index match, so return name match, if any |
654 |
//no exact index match, so return name match, if any |
598 |
return nameMatch; |
655 |
return nameMatch; |
Lines 645-651
public class BuildManager implements ICoreConstants, IManager, ILifecycleListene
Link Here
|
645 |
IResourceDelta getDelta(IProject project) { |
702 |
IResourceDelta getDelta(IProject project) { |
646 |
try { |
703 |
try { |
647 |
lock.acquire(); |
704 |
lock.acquire(); |
648 |
if (currentTree == null) { |
705 |
if (currentTree.get() == null) { |
649 |
if (Policy.DEBUG_BUILD_FAILURE) |
706 |
if (Policy.DEBUG_BUILD_FAILURE) |
650 |
Policy.debug("Build: no tree for delta " + debugBuilder() + " [" + debugProject() + "]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
707 |
Policy.debug("Build: no tree for delta " + debugBuilder() + " [" + debugProject() + "]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
651 |
return null; |
708 |
return null; |
Lines 657-663
public class BuildManager implements ICoreConstants, IManager, ILifecycleListene
Link Here
|
657 |
return null; |
714 |
return null; |
658 |
} |
715 |
} |
659 |
//check if this project has changed |
716 |
//check if this project has changed |
660 |
if (currentDelta != null && currentDelta.findNodeAt(project.getFullPath()) == null) { |
717 |
if (currentDelta.get() != null && currentDelta.get().findNodeAt(project.getFullPath()) == null) { |
661 |
//if the project never existed (not in delta and not in current tree), return null |
718 |
//if the project never existed (not in delta and not in current tree), return null |
662 |
if (!project.exists()) |
719 |
if (!project.exists()) |
663 |
return null; |
720 |
return null; |
Lines 665-671
public class BuildManager implements ICoreConstants, IManager, ILifecycleListene
Link Here
|
665 |
return ResourceDeltaFactory.newEmptyDelta(project); |
722 |
return ResourceDeltaFactory.newEmptyDelta(project); |
666 |
} |
723 |
} |
667 |
//now check against the cache |
724 |
//now check against the cache |
668 |
IResourceDelta result = (IResourceDelta) deltaCache.getDelta(project.getFullPath(), currentLastBuiltTree, currentTree); |
725 |
IResourceDelta result = (IResourceDelta) deltaCache.getDelta(project.getFullPath(), currentLastBuiltTree.get(), currentTree.get()); |
669 |
if (result != null) |
726 |
if (result != null) |
670 |
return result; |
727 |
return result; |
671 |
|
728 |
|
Lines 674-681
public class BuildManager implements ICoreConstants, IManager, ILifecycleListene
Link Here
|
674 |
startTime = System.currentTimeMillis(); |
731 |
startTime = System.currentTimeMillis(); |
675 |
Policy.debug("Computing delta for project: " + project.getName()); //$NON-NLS-1$ |
732 |
Policy.debug("Computing delta for project: " + project.getName()); //$NON-NLS-1$ |
676 |
} |
733 |
} |
677 |
result = ResourceDeltaFactory.computeDelta(workspace, currentLastBuiltTree, currentTree, project.getFullPath(), -1); |
734 |
result = ResourceDeltaFactory.computeDelta(workspace, currentLastBuiltTree.get(), currentTree.get(), project.getFullPath(), -1); |
678 |
deltaCache.cache(project.getFullPath(), currentLastBuiltTree, currentTree, result); |
735 |
deltaCache.cache(project.getFullPath(), currentLastBuiltTree.get(), currentTree.get(), result); |
679 |
if (Policy.DEBUG_BUILD_FAILURE && result == null) |
736 |
if (Policy.DEBUG_BUILD_FAILURE && result == null) |
680 |
Policy.debug("Build: no delta " + debugBuilder() + " [" + debugProject() + "] " + project.getFullPath()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
737 |
Policy.debug("Build: no delta " + debugBuilder() + " [" + debugProject() + "] " + project.getFullPath()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
681 |
if (Policy.DEBUG_BUILD_DELTA) { |
738 |
if (Policy.DEBUG_BUILD_DELTA) { |
Lines 692-698
public class BuildManager implements ICoreConstants, IManager, ILifecycleListene
Link Here
|
692 |
/** |
749 |
/** |
693 |
* Returns the safe runnable instance for invoking a builder |
750 |
* Returns the safe runnable instance for invoking a builder |
694 |
*/ |
751 |
*/ |
695 |
private ISafeRunnable getSafeRunnable(final int trigger, final Map<String, String> args, final MultiStatus status, final IProgressMonitor monitor) { |
752 |
private ISafeRunnable getSafeRunnable(final int trigger, final Map<String, String> args, final MultiStatus status, final IProgressMonitor monitor, final InternalBuilder builder) { |
696 |
return new ISafeRunnable() { |
753 |
return new ISafeRunnable() { |
697 |
public void handleException(Throwable e) { |
754 |
public void handleException(Throwable e) { |
698 |
if (e instanceof OperationCanceledException) { |
755 |
if (e instanceof OperationCanceledException) { |
Lines 700-717
public class BuildManager implements ICoreConstants, IManager, ILifecycleListene
Link Here
|
700 |
Policy.debug("Build canceled"); //$NON-NLS-1$ |
757 |
Policy.debug("Build canceled"); //$NON-NLS-1$ |
701 |
//just discard built state when a builder cancels, to ensure |
758 |
//just discard built state when a builder cancels, to ensure |
702 |
//that it is called again on the very next build. |
759 |
//that it is called again on the very next build. |
703 |
currentBuilder.forgetLastBuiltState(); |
760 |
builder.forgetLastBuiltState(); |
704 |
throw (OperationCanceledException) e; |
761 |
throw (OperationCanceledException) e; |
705 |
} |
762 |
} |
706 |
//ResourceStats.buildException(e); |
763 |
//ResourceStats.buildException(e); |
707 |
// don't log the exception....it is already being logged in SafeRunner#run |
764 |
// don't log the exception....it is already being logged in SafeRunner#run |
708 |
|
765 |
|
709 |
//add a generic message to the MultiStatus |
766 |
//add a generic message to the MultiStatus |
710 |
String builderName = currentBuilder.getLabel(); |
767 |
String builderName = builder.getLabel(); |
711 |
if (builderName == null || builderName.length() == 0) |
768 |
if (builderName == null || builderName.length() == 0) |
712 |
builderName = currentBuilder.getClass().getName(); |
769 |
builderName = builder.getClass().getName(); |
713 |
String pluginId = currentBuilder.getPluginId(); |
770 |
String pluginId = builder.getPluginId(); |
714 |
String message = NLS.bind(Messages.events_builderError, builderName, currentBuilder.getProject().getName()); |
771 |
String message = NLS.bind(Messages.events_builderError, builderName, builder.getProject().getName()); |
715 |
status.add(new Status(IStatus.ERROR, pluginId, IResourceStatus.BUILD_FAILED, message, e)); |
772 |
status.add(new Status(IStatus.ERROR, pluginId, IResourceStatus.BUILD_FAILED, message, e)); |
716 |
|
773 |
|
717 |
//add the exception status to the MultiStatus |
774 |
//add the exception status to the MultiStatus |
Lines 722-734
public class BuildManager implements ICoreConstants, IManager, ILifecycleListene
Link Here
|
722 |
public void run() throws Exception { |
779 |
public void run() throws Exception { |
723 |
IProject[] prereqs = null; |
780 |
IProject[] prereqs = null; |
724 |
//invoke the appropriate build method depending on the trigger |
781 |
//invoke the appropriate build method depending on the trigger |
725 |
if (trigger != IncrementalProjectBuilder.CLEAN_BUILD) |
782 |
if (trigger == IncrementalProjectBuilder.CLEAN_BUILD) { |
726 |
prereqs = currentBuilder.build(trigger, args, monitor); |
783 |
builder.clean(monitor); |
727 |
else |
784 |
} else { |
728 |
currentBuilder.clean(monitor); |
785 |
prereqs = builder.build(trigger, args, monitor); |
729 |
if (prereqs == null) |
786 |
} |
730 |
prereqs = new IProject[0]; |
787 |
|
731 |
currentBuilder.setInterestingProjects(prereqs.clone()); |
788 |
if (prereqs == null) prereqs = new IProject[0]; |
|
|
789 |
|
790 |
builder.setInterestingProjects(prereqs.clone()); |
732 |
} |
791 |
} |
733 |
}; |
792 |
}; |
734 |
} |
793 |
} |
Lines 920-928
public class BuildManager implements ICoreConstants, IManager, ILifecycleListene
Link Here
|
920 |
* to the given project, and false otherwise. |
979 |
* to the given project, and false otherwise. |
921 |
*/ |
980 |
*/ |
922 |
private boolean isInterestingProject(IProject project) { |
981 |
private boolean isInterestingProject(IProject project) { |
923 |
if (project.equals(currentBuilder.getProject())) |
982 |
if (project.equals(currentBuilder.get().getProject())) |
924 |
return true; |
983 |
return true; |
925 |
IProject[] interestingProjects = currentBuilder.getInterestingProjects(); |
984 |
IProject[] interestingProjects = currentBuilder.get().getInterestingProjects(); |
926 |
for (int i = 0; i < interestingProjects.length; i++) { |
985 |
for (int i = 0; i < interestingProjects.length; i++) { |
927 |
if (interestingProjects[i].equals(project)) { |
986 |
if (interestingProjects[i].equals(project)) { |
928 |
return true; |
987 |
return true; |
Lines 950-956
public class BuildManager implements ICoreConstants, IManager, ILifecycleListene
Link Here
|
950 |
case IncrementalProjectBuilder.FULL_BUILD : |
1009 |
case IncrementalProjectBuilder.FULL_BUILD : |
951 |
return true; |
1010 |
return true; |
952 |
case IncrementalProjectBuilder.INCREMENTAL_BUILD : |
1011 |
case IncrementalProjectBuilder.INCREMENTAL_BUILD : |
953 |
if (currentBuilder.callOnEmptyDelta()) |
1012 |
if (currentBuilder.get().callOnEmptyDelta()) |
954 |
return true; |
1013 |
return true; |
955 |
//fall through and check if there is a delta |
1014 |
//fall through and check if there is a delta |
956 |
} |
1015 |
} |
Lines 959-978
public class BuildManager implements ICoreConstants, IManager, ILifecycleListene
Link Here
|
959 |
ElementTree oldTree = builder.getLastBuiltTree(); |
1018 |
ElementTree oldTree = builder.getLastBuiltTree(); |
960 |
ElementTree newTree = workspace.getElementTree(); |
1019 |
ElementTree newTree = workspace.getElementTree(); |
961 |
long start = System.currentTimeMillis(); |
1020 |
long start = System.currentTimeMillis(); |
962 |
currentDelta = (DeltaDataTree) deltaTreeCache.getDelta(null, oldTree, newTree); |
1021 |
currentDelta.set((DeltaDataTree) deltaTreeCache.getDelta(null, oldTree, newTree)); |
963 |
if (currentDelta == null) { |
1022 |
if (currentDelta.get() == null) { |
964 |
if (Policy.DEBUG_BUILD_NEEDED) { |
1023 |
if (Policy.DEBUG_BUILD_NEEDED) { |
965 |
String message = "Checking if need to build. Starting delta computation between: " + oldTree.toString() + " and " + newTree.toString(); //$NON-NLS-1$ //$NON-NLS-2$ |
1024 |
String message = "Checking if need to build. Starting delta computation between: " + oldTree.toString() + " and " + newTree.toString(); //$NON-NLS-1$ //$NON-NLS-2$ |
966 |
Policy.debug(message); |
1025 |
Policy.debug(message); |
967 |
} |
1026 |
} |
968 |
currentDelta = newTree.getDataTree().forwardDeltaWith(oldTree.getDataTree(), ResourceComparator.getBuildComparator()); |
1027 |
currentDelta.set(newTree.getDataTree().forwardDeltaWith(oldTree.getDataTree(), ResourceComparator.getBuildComparator())); |
969 |
if (Policy.DEBUG_BUILD_NEEDED) |
1028 |
if (Policy.DEBUG_BUILD_NEEDED) |
970 |
Policy.debug("End delta computation. (" + (System.currentTimeMillis() - start) + "ms)."); //$NON-NLS-1$ //$NON-NLS-2$ |
1029 |
Policy.debug("End delta computation. (" + (System.currentTimeMillis() - start) + "ms)."); //$NON-NLS-1$ //$NON-NLS-2$ |
971 |
deltaTreeCache.cache(null, oldTree, newTree, currentDelta); |
1030 |
deltaTreeCache.cache(null, oldTree, newTree, currentDelta.get()); |
972 |
} |
1031 |
} |
973 |
|
1032 |
|
974 |
//search for the builder's project |
1033 |
//search for the builder's project |
975 |
if (currentDelta.findNodeAt(builder.getProject().getFullPath()) != null) { |
1034 |
if (currentDelta.get().findNodeAt(builder.getProject().getFullPath()) != null) { |
976 |
if (Policy.DEBUG_BUILD_NEEDED) |
1035 |
if (Policy.DEBUG_BUILD_NEEDED) |
977 |
Policy.debug(toString(builder) + " needs building because of changes in: " + builder.getProject().getName()); //$NON-NLS-1$ |
1036 |
Policy.debug(toString(builder) + " needs building because of changes in: " + builder.getProject().getName()); //$NON-NLS-1$ |
978 |
return true; |
1037 |
return true; |
Lines 981-987
public class BuildManager implements ICoreConstants, IManager, ILifecycleListene
Link Here
|
981 |
//search for builder's interesting projects |
1040 |
//search for builder's interesting projects |
982 |
IProject[] projects = builder.getInterestingProjects(); |
1041 |
IProject[] projects = builder.getInterestingProjects(); |
983 |
for (int i = 0; i < projects.length; i++) { |
1042 |
for (int i = 0; i < projects.length; i++) { |
984 |
if (currentDelta.findNodeAt(projects[i].getFullPath()) != null) { |
1043 |
if (currentDelta.get().findNodeAt(projects[i].getFullPath()) != null) { |
985 |
if (Policy.DEBUG_BUILD_NEEDED) |
1044 |
if (Policy.DEBUG_BUILD_NEEDED) |
986 |
Policy.debug(toString(builder) + " needs building because of changes in: " + projects[i].getName()); //$NON-NLS-1$ |
1045 |
Policy.debug(toString(builder) + " needs building because of changes in: " + projects[i].getName()); //$NON-NLS-1$ |
987 |
return true; |
1046 |
return true; |
Lines 1143-1146
public class BuildManager implements ICoreConstants, IManager, ILifecycleListene
Link Here
|
1143 |
Policy.log(status); |
1202 |
Policy.log(status); |
1144 |
return workspace.getRoot(); |
1203 |
return workspace.getRoot(); |
1145 |
} |
1204 |
} |
|
|
1205 |
|
1206 |
public void buildParallel(final int trigger, IProgressMonitor monitor, IBuildConfiguration[] configs) throws CoreException { |
1207 |
|
1208 |
final boolean clean = (trigger == IncrementalProjectBuilder.PARALLEL_CLEAN_BUILD); |
1209 |
|
1210 |
long start = System.currentTimeMillis(); |
1211 |
if (clean) { |
1212 |
Policy.log(new ResourceStatus(IStatus.INFO, "Starting parallel cleaning of " + configs.length + " projects...")); |
1213 |
} else { |
1214 |
Policy.log(new ResourceStatus(IStatus.INFO, "Starting parallel build of " + configs.length + " projects...")); |
1215 |
} |
1216 |
final SharedProgressMonitor sharedProgress = new SharedProgressMonitor(Policy.monitorFor(monitor)); |
1217 |
|
1218 |
List<IProject> projects = new ArrayList<IProject>(); |
1219 |
DirectedGraphs<IProject> directedGraphs = new DirectedGraphs<IProject>(); |
1220 |
for (IBuildConfiguration config : configs) { |
1221 |
projects.add(config.getProject()); |
1222 |
directedGraphs.addNode(new Node<IProject>(config.getProject())); |
1223 |
} |
1224 |
|
1225 |
// cleaning does not require building the graph |
1226 |
if (trigger == IncrementalProjectBuilder.PARALLEL_FULL_BUILD) { |
1227 |
for (IProject project : projects) { |
1228 |
if (!project.isAccessible()) |
1229 |
continue; |
1230 |
ProjectDescription desc = ((Project)project).internalGetDescription(); |
1231 |
if (desc == null) |
1232 |
continue; |
1233 |
IProject[] refs = desc.getAllReferences(false); |
1234 |
Node<IProject> node = directedGraphs.getNodeWithContent(project); |
1235 |
for (IProject referencedProject : refs) { |
1236 |
Node<IProject> node2 = directedGraphs.getNodeWithContent(referencedProject); |
1237 |
if(node2 != null) { |
1238 |
node2.addOutgoingEdge(node); |
1239 |
} |
1240 |
} |
1241 |
} |
1242 |
} |
1243 |
|
1244 |
hookStartBuild(configs, trigger); |
1245 |
|
1246 |
final MultiStatus status = new MultiStatus(ResourcesPlugin.PI_RESOURCES, IResourceStatus.INTERNAL_ERROR, Messages.events_errors, null); |
1247 |
|
1248 |
if (clean) { |
1249 |
sharedProgress.beginTask("Cleaning projects in parallel:", projects.size()); |
1250 |
} else { |
1251 |
sharedProgress.beginTask("Building projects in parallel:", projects.size()); |
1252 |
} |
1253 |
|
1254 |
ThreadPoolBuilder threadPoolBuilder = new ThreadPoolBuilder(); |
1255 |
try { |
1256 |
IBuildExecutor buildExecutor = new IBuildExecutor() { |
1257 |
public void executeBuild(IBuildDescription buildDescription, SharedProgressMonitor sharedProgress) { |
1258 |
IProgressMonitor progressMonitor = new NullProgressMonitor(); |
1259 |
try { |
1260 |
sharedProgress.addProjectName(buildDescription.getBuildConfiguration().getProject().getName()); |
1261 |
basicBuild(buildDescription.getBuildConfiguration(), trigger, buildDescription.getBuildContext(), status, progressMonitor); |
1262 |
} finally { |
1263 |
sharedProgress.removeProjectName(buildDescription.getBuildConfiguration().getProject().getName()); |
1264 |
sharedProgress.worked(1); |
1265 |
} |
1266 |
}}; |
1267 |
threadPoolBuilder.run(directedGraphs, buildExecutor, sharedProgress); |
1268 |
} catch (InterruptedException e) { |
1269 |
status.add(new Status(IStatus.ERROR, ResourcesPlugin.PI_RESOURCES, Messages.events_errors, e)); |
1270 |
} finally { |
1271 |
hookEndBuild(trigger); |
1272 |
long finish = System.currentTimeMillis(); |
1273 |
if (clean) { |
1274 |
Policy.log(new ResourceStatus(IStatus.INFO, "Finished parallel clean in " + (finish - start) + "ms")); |
1275 |
} else { |
1276 |
Policy.log(new ResourceStatus(IStatus.INFO, "Finished parallel build in " + (finish - start) + "ms")); |
1277 |
} |
1278 |
sharedProgress.done(); |
1279 |
} |
1280 |
} |
1281 |
|
1282 |
private IncrementalProjectBuilder getParallelBuilder(IBuildConfiguration buildConfiguration, BuildCommand command, int buildSpecIndex, MultiStatus status, IBuildContext buildContext) throws CoreException { |
1283 |
// always construct a new builder for parallel builds (think about pooling here) |
1284 |
InternalBuilder result = initializeBuilder(command.getBuilderName(), buildConfiguration, buildSpecIndex, status); |
1285 |
command.setBuilders(result); |
1286 |
result.setCommand(command); |
1287 |
result.setBuildConfig(buildConfiguration); |
1288 |
result.startupOnInitialize(); |
1289 |
// } |
1290 |
|
1291 |
if (!validateNature(result, command.getBuilderName())) { |
1292 |
//skip this builder and null its last built tree because it is invalid |
1293 |
//if the nature gets added or re-enabled a full build will be triggered |
1294 |
result.setLastBuiltTree(null); |
1295 |
return null; |
1296 |
} |
1297 |
return (IncrementalProjectBuilder) result; |
1298 |
} |
1146 |
} |
1299 |
} |