|
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