Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,10 @@ private Result<ProjectDependencyGraph> sessionDependencyGraph(final MavenSession
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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
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;
Expand All @@ -35,11 +36,11 @@
*/
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.
Expand All @@ -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;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand All @@ -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();
Expand Down