1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.project.collector;
20
21 import javax.inject.Inject;
22 import javax.inject.Named;
23 import javax.inject.Singleton;
24
25 import java.io.File;
26 import java.util.ArrayList;
27 import java.util.Collections;
28 import java.util.List;
29 import java.util.Objects;
30 import java.util.function.Predicate;
31
32 import org.apache.maven.execution.MavenExecutionRequest;
33 import org.apache.maven.model.Plugin;
34 import org.apache.maven.model.building.ModelProblem;
35 import org.apache.maven.model.locator.ModelLocator;
36 import org.apache.maven.plugin.PluginManagerException;
37 import org.apache.maven.plugin.PluginResolutionException;
38 import org.apache.maven.project.MavenProject;
39 import org.apache.maven.project.ProjectBuildingException;
40 import org.apache.maven.project.ProjectBuildingResult;
41 import org.eclipse.aether.resolution.ArtifactResolutionException;
42 import org.eclipse.aether.transfer.ArtifactNotFoundException;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
45
46
47
48
49 @Named("MultiModuleCollectionStrategy")
50 @Singleton
51 public class MultiModuleCollectionStrategy implements ProjectCollectionStrategy {
52 private static final Logger LOGGER = LoggerFactory.getLogger(MultiModuleCollectionStrategy.class);
53 private final ModelLocator modelLocator;
54 private final ProjectsSelector projectsSelector;
55
56 @Inject
57 public MultiModuleCollectionStrategy(ModelLocator modelLocator, ProjectsSelector projectsSelector) {
58 this.modelLocator = modelLocator;
59 this.projectsSelector = projectsSelector;
60 }
61
62 @Override
63 public List<MavenProject> collectProjects(MavenExecutionRequest request) throws ProjectBuildingException {
64 File moduleProjectPomFile = getMultiModuleProjectPomFile(request);
65 List<File> files = Collections.singletonList(moduleProjectPomFile.getAbsoluteFile());
66 try {
67 List<MavenProject> projects = projectsSelector.selectProjects(files, request);
68 boolean isRequestedProjectCollected = isRequestedProjectCollected(request, projects);
69 if (isRequestedProjectCollected) {
70 return projects;
71 } else {
72 LOGGER.debug(
73 "Multi module project collection failed:{}"
74 + "Detected a POM file next to a .mvn directory in a parent directory ({}). "
75 + "Maven assumed that POM file to be the parent of the requested project ({}), but it turned "
76 + "out that it was not. Another project collection strategy will be executed as result.",
77 System.lineSeparator(),
78 moduleProjectPomFile.getAbsolutePath(),
79 request.getPom().getAbsolutePath());
80 return Collections.emptyList();
81 }
82 } catch (ProjectBuildingException e) {
83 boolean fallThrough = isModuleOutsideRequestScopeDependingOnPluginModule(request, e);
84
85 if (fallThrough) {
86 LOGGER.debug(
87 "Multi module project collection failed:{}"
88 + "Detected that one of the modules of this multi-module project uses another module as "
89 + "plugin extension which still needed to be built. This is not possible within the same "
90 + "reactor build. Another project collection strategy will be executed as result.",
91 System.lineSeparator());
92 return Collections.emptyList();
93 }
94
95 throw e;
96 }
97 }
98
99 private File getMultiModuleProjectPomFile(MavenExecutionRequest request) {
100 File multiModuleProjectDirectory = request.getMultiModuleProjectDirectory();
101 if (request.getPom().getParentFile().equals(multiModuleProjectDirectory)) {
102 return request.getPom();
103 } else {
104 File multiModuleProjectPom = modelLocator.locateExistingPom(multiModuleProjectDirectory);
105 if (multiModuleProjectPom == null) {
106 LOGGER.info(
107 "Maven detected that the requested POM file is part of a multi-module project, "
108 + "but could not find a pom.xml file in the multi-module root directory '{}'.",
109 multiModuleProjectDirectory);
110 LOGGER.info(
111 "The reactor is limited to all projects under: {}",
112 request.getPom().getParent());
113 return request.getPom();
114 }
115
116 return multiModuleProjectPom;
117 }
118 }
119
120
121
122
123
124
125
126
127 private boolean isRequestedProjectCollected(MavenExecutionRequest request, List<MavenProject> projects) {
128 return projects.stream().map(MavenProject::getFile).anyMatch(request.getPom()::equals);
129 }
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145 private boolean isModuleOutsideRequestScopeDependingOnPluginModule(
146 MavenExecutionRequest request, ProjectBuildingException exception) {
147 return exception.getResults().stream()
148 .map(ProjectBuildingResult::getProject)
149 .filter(Objects::nonNull)
150 .filter(project -> request.getPom().equals(project.getFile()))
151 .findFirst()
152 .map(requestPomProject -> {
153 List<MavenProject> modules = requestPomProject.getCollectedProjects() != null
154 ? requestPomProject.getCollectedProjects()
155 : Collections.emptyList();
156 List<MavenProject> projectsInRequestScope = new ArrayList<>(modules);
157 projectsInRequestScope.add(requestPomProject);
158
159 Predicate<ProjectBuildingResult> projectsOutsideOfRequestScope =
160 pr -> !projectsInRequestScope.contains(pr.getProject());
161
162 Predicate<Exception> pluginArtifactNotFoundException = exc -> exc instanceof PluginManagerException
163 && exc.getCause() instanceof PluginResolutionException
164 && exc.getCause().getCause() instanceof ArtifactResolutionException
165 && exc.getCause().getCause().getCause() instanceof ArtifactNotFoundException;
166
167 Predicate<Plugin> isPluginPartOfRequestScope = plugin -> projectsInRequestScope.stream()
168 .anyMatch(project -> project.getGroupId().equals(plugin.getGroupId())
169 && project.getArtifactId().equals(plugin.getArtifactId())
170 && project.getVersion().equals(plugin.getVersion()));
171
172 return exception.getResults().stream()
173 .filter(projectsOutsideOfRequestScope)
174 .flatMap(projectBuildingResult -> projectBuildingResult.getProblems().stream())
175 .map(ModelProblem::getException)
176 .filter(pluginArtifactNotFoundException)
177 .map(exc -> ((PluginResolutionException) exc.getCause()).getPlugin())
178 .anyMatch(isPluginPartOfRequestScope);
179 })
180 .orElse(false);
181 }
182 }