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

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


The following commit(s) were added to refs/heads/master by this push:
     new 7ea795b789 [MNG-8256] FilteredProjectDependencyGraph fix for 
non-transitive case (#1723)
7ea795b789 is described below

commit 7ea795b789cb7b9b360408557acbae29aeb5732b
Author: Tamas Cservenak <[email protected]>
AuthorDate: Thu Sep 12 22:50:39 2024 +0200

    [MNG-8256] FilteredProjectDependencyGraph fix for non-transitive case 
(#1723)
    
    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      | 40 ++++++++++++++--------
 .../graph/DefaultProjectDependencyGraphTest.java   | 17 +++++++++
 3 files changed, 47 insertions(+), 16 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 02d935df4f..93c81d830d 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
@@ -120,8 +120,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 2d6612e3aa..feb06ec7c2 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
@@ -34,11 +34,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.
@@ -50,46 +50,58 @@ class FilteredProjectDependencyGraph implements 
ProjectDependencyGraph {
             ProjectDependencyGraph projectDependencyGraph, Collection<? 
extends MavenProject> whiteList) {
         this.projectDependencyGraph =
                 Objects.requireNonNull(projectDependencyGraph, 
"projectDependencyGraph cannot be null");
-
         this.whiteList = new IdentityHashMap<>();
-
         for (MavenProject project : whiteList) {
             this.whiteList.put(project, null);
         }
+        this.sortedProjects = 
projectDependencyGraph.getSortedProjects().stream()
+                .filter(this.whiteList::containsKey)
+                .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 9d68de0190..fab4c1cfb1 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
@@ -29,6 +29,7 @@ import org.apache.maven.project.MavenProject;
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 /**
  */
@@ -36,6 +37,10 @@ class DefaultProjectDependencyGraphTest {
 
     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");
@@ -47,6 +52,18 @@ class DefaultProjectDependencyGraphTest {
 
     private final MavenProject transitiveOnly = 
createProject(Arrays.asList(toDependency(depender3)), "depender5");
 
+    @Test
+    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));
+    }
+
     @Test
     void testGetSortedProjects() throws DuplicateProjectException, 
CycleDetectedException {
         ProjectDependencyGraph graph = new 
DefaultProjectDependencyGraph(Arrays.asList(depender1, aProject));

Reply via email to