This is an automated email from the ASF dual-hosted git repository.

cstamas pushed a commit to branch maven-3.9.x
in repository https://gitbox.apache.org/repos/asf/maven.git


The following commit(s) were added to refs/heads/maven-3.9.x by this push:
     new 45201347c4 [MNG-8256] FilteredProjectDependencyGraph fix for 
non-transitive case (#1724)
45201347c4 is described below

commit 45201347c417896b57159221130333f5fa4bbfb6
Author: Tamas Cservenak <[email protected]>
AuthorDate: Thu Sep 12 22:50:55 2024 +0200

    [MNG-8256] FilteredProjectDependencyGraph fix for non-transitive case 
(#1724)
    
    The `FilteredProjectDependencyGraph` class fix for non-transitive case and 
an UT. Also contains some improvement in classes, making them immutable as 
intended.
    
    ---
    
    https://issues.apache.org/jira/browse/MNG-8256
---
 .../apache/maven/graph/DefaultGraphBuilder.java    |  6 ++-
 .../graph/FilteredProjectDependencyGraph.java      | 43 ++++++++++++++--------
 .../graph/DefaultProjectDependencyGraphTest.java   | 15 ++++++++
 3 files changed, 47 insertions(+), 17 deletions(-)

diff --git 
a/maven-core/src/main/java/org/apache/maven/graph/DefaultGraphBuilder.java 
b/maven-core/src/main/java/org/apache/maven/graph/DefaultGraphBuilder.java
index b2f00adec2..67fad2b6a6 100644
--- a/maven-core/src/main/java/org/apache/maven/graph/DefaultGraphBuilder.java
+++ b/maven-core/src/main/java/org/apache/maven/graph/DefaultGraphBuilder.java
@@ -94,8 +94,10 @@ public class DefaultGraphBuilder implements GraphBuilder {
         Result<ProjectDependencyGraph> result = null;
 
         if (session.getProjectDependencyGraph() != null || 
session.getProjects() != null) {
-            final ProjectDependencyGraph graph =
-                    new 
DefaultProjectDependencyGraph(session.getAllProjects(), session.getProjects());
+            ProjectDependencyGraph graph = new 
DefaultProjectDependencyGraph(session.getAllProjects());
+            if (session.getProjects() != null) {
+                graph = new FilteredProjectDependencyGraph(graph, 
session.getProjects());
+            }
 
             result = Result.success(graph);
         }
diff --git 
a/maven-core/src/main/java/org/apache/maven/graph/FilteredProjectDependencyGraph.java
 
b/maven-core/src/main/java/org/apache/maven/graph/FilteredProjectDependencyGraph.java
index 96c008c78b..b05913c76f 100644
--- 
a/maven-core/src/main/java/org/apache/maven/graph/FilteredProjectDependencyGraph.java
+++ 
b/maven-core/src/main/java/org/apache/maven/graph/FilteredProjectDependencyGraph.java
@@ -24,6 +24,7 @@ import java.util.IdentityHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.stream.Collectors;
 
 import org.apache.maven.execution.ProjectDependencyGraph;
 import org.apache.maven.project.MavenProject;
@@ -35,11 +36,11 @@ import org.apache.maven.project.MavenProject;
  */
 class FilteredProjectDependencyGraph implements ProjectDependencyGraph {
 
-    private ProjectDependencyGraph projectDependencyGraph;
+    private final ProjectDependencyGraph projectDependencyGraph;
 
-    private Map<MavenProject, ?> whiteList;
+    private final Map<MavenProject, ?> whiteList;
 
-    private List<MavenProject> sortedProjects;
+    private final List<MavenProject> sortedProjects;
 
     /**
      * Creates a new project dependency graph from the specified graph.
@@ -51,46 +52,58 @@ class FilteredProjectDependencyGraph implements 
ProjectDependencyGraph {
             ProjectDependencyGraph projectDependencyGraph, Collection<? 
extends MavenProject> whiteList) {
         this.projectDependencyGraph =
                 Objects.requireNonNull(projectDependencyGraph, 
"projectDependencyGraph cannot be null");
-
-        this.whiteList = new IdentityHashMap<MavenProject, Object>();
-
+        this.whiteList = new IdentityHashMap<>();
         for (MavenProject project : whiteList) {
             this.whiteList.put(project, null);
         }
+        this.sortedProjects = 
projectDependencyGraph.getSortedProjects().stream()
+                .filter(this.whiteList::containsKey)
+                .collect(Collectors.toList());
     }
 
     /**
      * @since 3.5.0
      */
+    @Override
     public List<MavenProject> getAllProjects() {
         return this.projectDependencyGraph.getAllProjects();
     }
 
+    @Override
     public List<MavenProject> getSortedProjects() {
-        if (sortedProjects == null) {
-            sortedProjects = 
applyFilter(projectDependencyGraph.getSortedProjects());
-        }
-
         return new ArrayList<>(sortedProjects);
     }
 
+    @Override
     public List<MavenProject> getDownstreamProjects(MavenProject project, 
boolean transitive) {
-        return 
applyFilter(projectDependencyGraph.getDownstreamProjects(project, transitive));
+        return 
applyFilter(projectDependencyGraph.getDownstreamProjects(project, transitive), 
transitive, false);
     }
 
+    @Override
     public List<MavenProject> getUpstreamProjects(MavenProject project, 
boolean transitive) {
-        return applyFilter(projectDependencyGraph.getUpstreamProjects(project, 
transitive));
+        return applyFilter(projectDependencyGraph.getUpstreamProjects(project, 
transitive), transitive, true);
     }
 
-    private List<MavenProject> applyFilter(Collection<? extends MavenProject> 
projects) {
+    /**
+     * Filter out whitelisted projects with a big twist:
+     * Assume we have all projects {@code a, b, c} while active are {@code a, 
c} and relation among all projects
+     * is {@code a -> b -> c}. This method handles well the case for 
transitive list. But, for non-transitive we need
+     * to "pull in" transitive dependencies of eliminated projects, as for 
case above, the properly filtered list would
+     * be {@code a -> c}.
+     * <p>
+     * Original code would falsely report {@code a} project as "without 
dependencies", basically would lose link due
+     * filtering. This causes build ordering issues in concurrent builders.
+     */
+    private List<MavenProject> applyFilter(
+            Collection<? extends MavenProject> projects, boolean transitive, 
boolean upstream) {
         List<MavenProject> filtered = new ArrayList<>(projects.size());
-
         for (MavenProject project : projects) {
             if (whiteList.containsKey(project)) {
                 filtered.add(project);
+            } else if (!transitive) {
+                filtered.addAll(upstream ? getUpstreamProjects(project, false) 
: getDownstreamProjects(project, false));
             }
         }
-
         return filtered;
     }
 
diff --git 
a/maven-core/src/test/java/org/apache/maven/graph/DefaultProjectDependencyGraphTest.java
 
b/maven-core/src/test/java/org/apache/maven/graph/DefaultProjectDependencyGraphTest.java
index ce48390b03..9a5a8568de 100644
--- 
a/maven-core/src/test/java/org/apache/maven/graph/DefaultProjectDependencyGraphTest.java
+++ 
b/maven-core/src/test/java/org/apache/maven/graph/DefaultProjectDependencyGraphTest.java
@@ -35,6 +35,10 @@ public class DefaultProjectDependencyGraphTest extends 
TestCase {
 
     private final MavenProject aProject = createA();
 
+    private final MavenProject bProject = 
createProject(Arrays.asList(toDependency(aProject)), "bProject");
+
+    private final MavenProject cProject = 
createProject(Arrays.asList(toDependency(bProject)), "cProject");
+
     private final MavenProject depender1 = 
createProject(Arrays.asList(toDependency(aProject)), "depender1");
 
     private final MavenProject depender2 = 
createProject(Arrays.asList(toDependency(aProject)), "depender2");
@@ -46,6 +50,17 @@ public class DefaultProjectDependencyGraphTest extends 
TestCase {
 
     private final MavenProject transitiveOnly = 
createProject(Arrays.asList(toDependency(depender3)), "depender5");
 
+    public void testNonTransitiveFiltering() throws DuplicateProjectException, 
CycleDetectedException {
+        ProjectDependencyGraph graph = new FilteredProjectDependencyGraph(
+                new DefaultProjectDependencyGraph(Arrays.asList(aProject, 
bProject, cProject)),
+                Arrays.asList(aProject, cProject));
+        final List<MavenProject> sortedProjects = graph.getSortedProjects();
+        assertEquals(aProject, sortedProjects.get(0));
+        assertEquals(cProject, sortedProjects.get(1));
+
+        assertTrue(graph.getDownstreamProjects(aProject, 
false).contains(cProject));
+    }
+
     public void testGetSortedProjects() throws DuplicateProjectException, 
CycleDetectedException {
         ProjectDependencyGraph graph = new 
DefaultProjectDependencyGraph(Arrays.asList(depender1, aProject));
         final List<MavenProject> sortedProjects = graph.getSortedProjects();

Reply via email to