1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.lifecycle.internal.builder;
20
21 import javax.inject.Inject;
22 import javax.inject.Named;
23 import javax.inject.Singleton;
24
25 import java.util.List;
26 import java.util.Set;
27 import java.util.stream.Collectors;
28
29 import org.apache.maven.artifact.Artifact;
30 import org.apache.maven.execution.BuildFailure;
31 import org.apache.maven.execution.ExecutionEvent;
32 import org.apache.maven.execution.MavenExecutionRequest;
33 import org.apache.maven.execution.MavenSession;
34 import org.apache.maven.internal.MultilineMessageHelper;
35 import org.apache.maven.lifecycle.LifecycleExecutionException;
36 import org.apache.maven.lifecycle.LifecycleNotFoundException;
37 import org.apache.maven.lifecycle.LifecyclePhaseNotFoundException;
38 import org.apache.maven.lifecycle.MavenExecutionPlan;
39 import org.apache.maven.lifecycle.internal.DefaultLifecyclePluginAnalyzer;
40 import org.apache.maven.lifecycle.internal.ExecutionEventCatapult;
41 import org.apache.maven.lifecycle.internal.LifecycleDebugLogger;
42 import org.apache.maven.lifecycle.internal.LifecycleExecutionPlanCalculator;
43 import org.apache.maven.lifecycle.internal.ReactorContext;
44 import org.apache.maven.lifecycle.internal.TaskSegment;
45 import org.apache.maven.model.Plugin;
46 import org.apache.maven.plugin.InvalidPluginDescriptorException;
47 import org.apache.maven.plugin.MojoExecution;
48 import org.apache.maven.plugin.MojoNotFoundException;
49 import org.apache.maven.plugin.PluginDescriptorParsingException;
50 import org.apache.maven.plugin.PluginNotFoundException;
51 import org.apache.maven.plugin.PluginResolutionException;
52 import org.apache.maven.plugin.descriptor.MojoDescriptor;
53 import org.apache.maven.plugin.prefix.NoPluginFoundForPrefixException;
54 import org.apache.maven.plugin.version.PluginVersionResolutionException;
55 import org.apache.maven.project.MavenProject;
56 import org.codehaus.plexus.classworlds.realm.ClassRealm;
57 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory;
59
60
61
62
63
64
65
66
67 @Named
68 @Singleton
69 public class BuilderCommon {
70 private final Logger logger;
71 private final LifecycleDebugLogger lifecycleDebugLogger;
72 private final LifecycleExecutionPlanCalculator lifeCycleExecutionPlanCalculator;
73 private final ExecutionEventCatapult eventCatapult;
74
75 @Inject
76 public BuilderCommon(
77 LifecycleDebugLogger lifecycleDebugLogger,
78 LifecycleExecutionPlanCalculator lifeCycleExecutionPlanCalculator,
79 ExecutionEventCatapult eventCatapult) {
80 this.logger = LoggerFactory.getLogger(getClass());
81 this.lifecycleDebugLogger = lifecycleDebugLogger;
82 this.lifeCycleExecutionPlanCalculator = lifeCycleExecutionPlanCalculator;
83 this.eventCatapult = eventCatapult;
84 }
85
86
87
88
89 BuilderCommon(
90 LifecycleDebugLogger lifecycleDebugLogger,
91 LifecycleExecutionPlanCalculator lifeCycleExecutionPlanCalculator,
92 ExecutionEventCatapult eventCatapult,
93 Logger logger) {
94 this.lifecycleDebugLogger = lifecycleDebugLogger;
95 this.lifeCycleExecutionPlanCalculator = lifeCycleExecutionPlanCalculator;
96 this.eventCatapult = eventCatapult;
97 this.logger = logger;
98 }
99
100 public MavenExecutionPlan resolveBuildPlan(
101 MavenSession session, MavenProject project, TaskSegment taskSegment, Set<Artifact> projectArtifacts)
102 throws PluginNotFoundException, PluginResolutionException, LifecyclePhaseNotFoundException,
103 PluginDescriptorParsingException, MojoNotFoundException, InvalidPluginDescriptorException,
104 NoPluginFoundForPrefixException, LifecycleNotFoundException, PluginVersionResolutionException,
105 LifecycleExecutionException {
106 MavenExecutionPlan executionPlan =
107 lifeCycleExecutionPlanCalculator.calculateExecutionPlan(session, project, taskSegment.getTasks());
108
109 lifecycleDebugLogger.debugProjectPlan(project, executionPlan);
110
111 if (session.getRequest().getDegreeOfConcurrency() > 1
112 && session.getProjects().size() > 1) {
113 final Set<Plugin> unsafePlugins = executionPlan.getNonThreadSafePlugins();
114 if (!unsafePlugins.isEmpty()) {
115 for (String s : MultilineMessageHelper.format(
116 "Your build is requesting parallel execution, but this project contains the following "
117 + "plugin(s) that have goals not marked as thread-safe to support parallel execution.",
118 "While this /may/ work fine, please look for plugin updates and/or "
119 + "request plugins be made thread-safe.",
120 "If reporting an issue, report it against the plugin in question, not against Apache Maven.")) {
121 logger.warn(s);
122 }
123 if (logger.isDebugEnabled()) {
124 final Set<MojoDescriptor> unsafeGoals = executionPlan.getNonThreadSafeMojos();
125 logger.warn("The following goals are not marked as thread-safe in " + project.getName() + ":");
126 for (MojoDescriptor unsafeGoal : unsafeGoals) {
127 logger.warn(" " + unsafeGoal.getId());
128 }
129 } else {
130 logger.warn("The following plugins are not marked as thread-safe in " + project.getName() + ":");
131 for (Plugin unsafePlugin : unsafePlugins) {
132 logger.warn(" " + unsafePlugin.getId());
133 }
134 logger.warn("");
135 logger.warn("Enable verbose output (-X) to see precisely which goals are not marked as"
136 + " thread-safe.");
137 }
138 logger.warn(MultilineMessageHelper.separatorLine());
139 }
140 }
141
142 final String defaulModelId = DefaultLifecyclePluginAnalyzer.DEFAULTLIFECYCLEBINDINGS_MODELID;
143
144 List<String> unversionedPlugins = executionPlan.getMojoExecutions().stream()
145 .map(MojoExecution::getPlugin)
146 .filter(p -> p.getLocation("version") != null
147 && p.getLocation("version").getSource() != null
148 && defaulModelId.equals(
149 p.getLocation("version").getSource().getModelId()))
150 .distinct()
151 .map(Plugin::getArtifactId)
152 .collect(Collectors.toList());
153
154 if (!unversionedPlugins.isEmpty()) {
155 logger.warn("Version not locked for default bindings plugins " + unversionedPlugins
156 + ", you should define versions in pluginManagement section of your " + "pom.xml or parent");
157 }
158
159 return executionPlan;
160 }
161
162 public void handleBuildError(
163 final ReactorContext buildContext,
164 final MavenSession rootSession,
165 final MavenSession currentSession,
166 final MavenProject mavenProject,
167 Throwable t,
168 final long buildStartTime) {
169
170 long buildEndTime = System.currentTimeMillis();
171 buildContext.getResult().addException(t);
172 buildContext.getResult().addBuildSummary(new BuildFailure(mavenProject, buildEndTime - buildStartTime, t));
173
174
175 if (t instanceof Exception && !(t instanceof RuntimeException)) {
176 eventCatapult.fire(ExecutionEvent.Type.ProjectFailed, currentSession, null, (Exception) t);
177 }
178
179
180 if (t instanceof RuntimeException || !(t instanceof Exception)) {
181
182
183 buildContext.getReactorBuildStatus().halt();
184 } else if (MavenExecutionRequest.REACTOR_FAIL_NEVER.equals(rootSession.getReactorFailureBehavior())) {
185
186 } else if (MavenExecutionRequest.REACTOR_FAIL_AT_END.equals(rootSession.getReactorFailureBehavior())) {
187
188 buildContext.getReactorBuildStatus().blackList(mavenProject);
189 } else if (MavenExecutionRequest.REACTOR_FAIL_FAST.equals(rootSession.getReactorFailureBehavior())) {
190 buildContext.getReactorBuildStatus().halt();
191 } else {
192 logger.error("invalid reactor failure behavior " + rootSession.getReactorFailureBehavior());
193 buildContext.getReactorBuildStatus().halt();
194 }
195 }
196
197 public static void attachToThread(MavenProject currentProject) {
198 ClassRealm projectRealm = currentProject.getClassRealm();
199 if (projectRealm != null) {
200 Thread.currentThread().setContextClassLoader(projectRealm);
201 }
202 }
203
204
205
206
207 public static String getKey(MavenProject project) {
208 return project.getGroupId() + ':' + project.getArtifactId() + ':' + project.getVersion();
209 }
210 }