|
16 | 16 | import static org.eclipse.core.resources.IncrementalProjectBuilder.FULL_BUILD;
|
17 | 17 |
|
18 | 18 | import java.io.File;
|
| 19 | +import java.text.DateFormat; |
19 | 20 | import java.util.ArrayList;
|
20 | 21 | import java.util.Collection;
|
21 | 22 | import java.util.Collections;
|
| 23 | +import java.util.Date; |
22 | 24 | import java.util.HashSet;
|
23 | 25 | import java.util.LinkedHashMap;
|
24 | 26 | import java.util.LinkedHashSet;
|
25 | 27 | import java.util.List;
|
26 | 28 | import java.util.Map;
|
27 | 29 | import java.util.Set;
|
| 30 | +import java.util.concurrent.ConcurrentHashMap; |
28 | 31 | import java.util.concurrent.atomic.AtomicBoolean;
|
29 | 32 |
|
30 | 33 | import org.slf4j.Logger;
|
|
37 | 40 | import org.eclipse.core.resources.IResourceDelta;
|
38 | 41 | import org.eclipse.core.resources.IncrementalProjectBuilder;
|
39 | 42 | import org.eclipse.core.resources.ResourcesPlugin;
|
| 43 | +import org.eclipse.core.runtime.Adapters; |
40 | 44 | import org.eclipse.core.runtime.CoreException;
|
| 45 | +import org.eclipse.core.runtime.IAdaptable; |
41 | 46 | import org.eclipse.core.runtime.IPath;
|
42 | 47 | import org.eclipse.core.runtime.IProgressMonitor;
|
43 | 48 | import org.eclipse.core.runtime.QualifiedName;
|
@@ -78,6 +83,8 @@ public class MavenBuilderImpl {
|
78 | 83 |
|
79 | 84 | private final List<IIncrementalBuildFramework> incrementalBuildFrameworks;
|
80 | 85 |
|
| 86 | + private final Map<IProject, ProjectBuildState> deltaState = new ConcurrentHashMap<>(); |
| 87 | + |
81 | 88 | public MavenBuilderImpl(DeltaProvider deltaProvider) {
|
82 | 89 | this.deltaProvider = deltaProvider;
|
83 | 90 | this.incrementalBuildFrameworks = loadIncrementalBuildFrameworks();
|
@@ -113,9 +120,10 @@ public Set<IProject> build(MavenSession session, IMavenProjectFacade projectFaca
|
113 | 120 | if(!hasRelevantDelta(projectFacade, delta)) {
|
114 | 121 | return Set.of(project);
|
115 | 122 | }
|
116 |
| - |
| 123 | + ProjectBuildState buildState = deltaState.computeIfAbsent(project, ProjectBuildState::new); |
117 | 124 | final BuildResultCollector participantResults = new BuildResultCollector();
|
118 |
| - List<BuildContext> incrementalContexts = setupProjectBuildContext(project, kind, delta, participantResults); |
| 125 | + List<BuildContext> incrementalContexts = setupProjectBuildContext(project, kind, delta, participantResults, |
| 126 | + buildState); |
119 | 127 |
|
120 | 128 | debugBuildStart(debugHooks, projectFacade, kind, args, participants, delta, monitor);
|
121 | 129 |
|
@@ -184,7 +192,10 @@ public Set<IProject> build(MavenSession session, IMavenProjectFacade projectFaca
|
184 | 192 | // Process errors and warnings
|
185 | 193 | MavenExecutionResult result = session.getResult();
|
186 | 194 | processBuildResults(project, mavenProject, result, participantResults, buildErrors);
|
187 |
| - |
| 195 | + if(buildErrors.isEmpty()) { |
| 196 | + //we only commit this when there are no errors so just in case a failure is cased by a changed file it is again queried afterwards |
| 197 | + buildState.commit(); |
| 198 | + } |
188 | 199 | return dependencies;
|
189 | 200 | }
|
190 | 201 |
|
@@ -227,10 +238,12 @@ private boolean hasRelevantDelta(IMavenProjectFacade projectFacade, IResourceDel
|
227 | 238 | }
|
228 | 239 |
|
229 | 240 | private List<IIncrementalBuildFramework.BuildContext> setupProjectBuildContext(IProject project, int kind,
|
230 |
| - IResourceDelta delta, IIncrementalBuildFramework.BuildResultCollector results) throws CoreException { |
| 241 | + IResourceDelta delta, IIncrementalBuildFramework.BuildResultCollector results, ProjectBuildState buildState) |
| 242 | + throws CoreException { |
231 | 243 | List<IIncrementalBuildFramework.BuildContext> contexts = new ArrayList<>();
|
232 | 244 |
|
233 |
| - BuildDelta buildDelta = delta != null ? new EclipseResourceBuildDelta(delta) : null; |
| 245 | + BuildDelta buildDelta = delta != null ? new ProjectBuildStateDelta(buildState, new EclipseResourceBuildDelta(delta)) |
| 246 | + : null; |
234 | 247 | for(IIncrementalBuildFramework framework : incrementalBuildFrameworks) {
|
235 | 248 | contexts.add(framework.setupProjectBuildContext(project, kind, buildDelta, results));
|
236 | 249 | }
|
@@ -408,7 +421,7 @@ public void clean(MavenSession session, IMavenProjectFacade projectFacade,
|
408 | 421 |
|
409 | 422 | final BuildResultCollector participantResults = new BuildResultCollector();
|
410 | 423 | List<BuildContext> incrementalContexts = setupProjectBuildContext(project, IncrementalProjectBuilder.CLEAN_BUILD,
|
411 |
| - null, participantResults); |
| 424 | + null, participantResults, null); |
412 | 425 |
|
413 | 426 | Map<Throwable, MojoExecutionKey> buildErrors = new LinkedHashMap<>();
|
414 | 427 | try {
|
@@ -452,4 +465,64 @@ public void clean(MavenSession session, IMavenProjectFacade projectFacade,
|
452 | 465 | DeltaProvider getDeltaProvider() {
|
453 | 466 | return deltaProvider;
|
454 | 467 | }
|
| 468 | + |
| 469 | + private static final class ProjectBuildState { |
| 470 | + |
| 471 | + private long lastBuild; |
| 472 | + |
| 473 | + private IProject project; |
| 474 | + |
| 475 | + public ProjectBuildState(IProject project) { |
| 476 | + this.project = project; |
| 477 | + } |
| 478 | + |
| 479 | + public void commit() { |
| 480 | + this.lastBuild = System.currentTimeMillis(); |
| 481 | + } |
| 482 | + |
| 483 | + @Override |
| 484 | + public String toString() { |
| 485 | + return "BuildState for " + project + " lat reccorded timestamp " |
| 486 | + + DateFormat.getDateTimeInstance().format(new Date(lastBuild)); |
| 487 | + } |
| 488 | + } |
| 489 | + |
| 490 | + private static final class ProjectBuildStateDelta implements BuildDelta, IAdaptable { |
| 491 | + |
| 492 | + private ProjectBuildState buildState; |
| 493 | + |
| 494 | + private BuildDelta delegate; |
| 495 | + |
| 496 | + /** |
| 497 | + * @param buildState |
| 498 | + * @param eclipseResourceBuildDelta |
| 499 | + */ |
| 500 | + public ProjectBuildStateDelta(ProjectBuildState buildState, BuildDelta delegate) { |
| 501 | + this.buildState = buildState; |
| 502 | + this.delegate = delegate; |
| 503 | + } |
| 504 | + |
| 505 | + @Override |
| 506 | + public boolean hasDelta(File file) { |
| 507 | + //first check the delegate... |
| 508 | + if(delegate != null && delegate.hasDelta(file)) { |
| 509 | + return true; |
| 510 | + } |
| 511 | + //... now perform additional checks |
| 512 | + if(file.isFile()) { |
| 513 | + long lastModified = file.lastModified(); |
| 514 | + if(lastModified > buildState.lastBuild) { |
| 515 | + //if the file is modified after the last build timestamp we assume it was modified even though not part of the current delta! |
| 516 | + return true; |
| 517 | + } |
| 518 | + } |
| 519 | + return false; |
| 520 | + } |
| 521 | + |
| 522 | + @Override |
| 523 | + public <T> T getAdapter(Class<T> adapter) { |
| 524 | + return Adapters.adapt(delegate, adapter); |
| 525 | + } |
| 526 | + |
| 527 | + } |
455 | 528 | }
|
0 commit comments