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