mirror of https://github.com/apache/maven.git
[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
This commit is contained in:
parent
4c059c401c
commit
45201347c4
|
@ -94,8 +94,10 @@ public class DefaultGraphBuilder implements GraphBuilder {
|
||||||
Result<ProjectDependencyGraph> result = null;
|
Result<ProjectDependencyGraph> result = null;
|
||||||
|
|
||||||
if (session.getProjectDependencyGraph() != null || session.getProjects() != null) {
|
if (session.getProjectDependencyGraph() != null || session.getProjects() != null) {
|
||||||
final ProjectDependencyGraph graph =
|
ProjectDependencyGraph graph = new DefaultProjectDependencyGraph(session.getAllProjects());
|
||||||
new DefaultProjectDependencyGraph(session.getAllProjects(), session.getProjects());
|
if (session.getProjects() != null) {
|
||||||
|
graph = new FilteredProjectDependencyGraph(graph, session.getProjects());
|
||||||
|
}
|
||||||
|
|
||||||
result = Result.success(graph);
|
result = Result.success(graph);
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ import java.util.IdentityHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.apache.maven.execution.ProjectDependencyGraph;
|
import org.apache.maven.execution.ProjectDependencyGraph;
|
||||||
import org.apache.maven.project.MavenProject;
|
import org.apache.maven.project.MavenProject;
|
||||||
|
@ -35,11 +36,11 @@ import org.apache.maven.project.MavenProject;
|
||||||
*/
|
*/
|
||||||
class FilteredProjectDependencyGraph implements ProjectDependencyGraph {
|
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.
|
* Creates a new project dependency graph from the specified graph.
|
||||||
|
@ -51,46 +52,58 @@ class FilteredProjectDependencyGraph implements ProjectDependencyGraph {
|
||||||
ProjectDependencyGraph projectDependencyGraph, Collection<? extends MavenProject> whiteList) {
|
ProjectDependencyGraph projectDependencyGraph, Collection<? extends MavenProject> whiteList) {
|
||||||
this.projectDependencyGraph =
|
this.projectDependencyGraph =
|
||||||
Objects.requireNonNull(projectDependencyGraph, "projectDependencyGraph cannot be null");
|
Objects.requireNonNull(projectDependencyGraph, "projectDependencyGraph cannot be null");
|
||||||
|
this.whiteList = new IdentityHashMap<>();
|
||||||
this.whiteList = new IdentityHashMap<MavenProject, Object>();
|
|
||||||
|
|
||||||
for (MavenProject project : whiteList) {
|
for (MavenProject project : whiteList) {
|
||||||
this.whiteList.put(project, null);
|
this.whiteList.put(project, null);
|
||||||
}
|
}
|
||||||
|
this.sortedProjects = projectDependencyGraph.getSortedProjects().stream()
|
||||||
|
.filter(this.whiteList::containsKey)
|
||||||
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @since 3.5.0
|
* @since 3.5.0
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public List<MavenProject> getAllProjects() {
|
public List<MavenProject> getAllProjects() {
|
||||||
return this.projectDependencyGraph.getAllProjects();
|
return this.projectDependencyGraph.getAllProjects();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public List<MavenProject> getSortedProjects() {
|
public List<MavenProject> getSortedProjects() {
|
||||||
if (sortedProjects == null) {
|
|
||||||
sortedProjects = applyFilter(projectDependencyGraph.getSortedProjects());
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ArrayList<>(sortedProjects);
|
return new ArrayList<>(sortedProjects);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public List<MavenProject> getDownstreamProjects(MavenProject project, boolean transitive) {
|
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) {
|
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());
|
List<MavenProject> filtered = new ArrayList<>(projects.size());
|
||||||
|
|
||||||
for (MavenProject project : projects) {
|
for (MavenProject project : projects) {
|
||||||
if (whiteList.containsKey(project)) {
|
if (whiteList.containsKey(project)) {
|
||||||
filtered.add(project);
|
filtered.add(project);
|
||||||
|
} else if (!transitive) {
|
||||||
|
filtered.addAll(upstream ? getUpstreamProjects(project, false) : getDownstreamProjects(project, false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return filtered;
|
return filtered;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,10 @@ public class DefaultProjectDependencyGraphTest extends TestCase {
|
||||||
|
|
||||||
private final MavenProject aProject = createA();
|
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 depender1 = createProject(Arrays.asList(toDependency(aProject)), "depender1");
|
||||||
|
|
||||||
private final MavenProject depender2 = createProject(Arrays.asList(toDependency(aProject)), "depender2");
|
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");
|
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 {
|
public void testGetSortedProjects() throws DuplicateProjectException, CycleDetectedException {
|
||||||
ProjectDependencyGraph graph = new DefaultProjectDependencyGraph(Arrays.asList(depender1, aProject));
|
ProjectDependencyGraph graph = new DefaultProjectDependencyGraph(Arrays.asList(depender1, aProject));
|
||||||
final List<MavenProject> sortedProjects = graph.getSortedProjects();
|
final List<MavenProject> sortedProjects = graph.getSortedProjects();
|
||||||
|
|
Loading…
Reference in New Issue