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.concurrent;
20
21 import javax.inject.Inject;
22 import javax.inject.Named;
23 import javax.inject.Singleton;
24
25 import java.util.ArrayList;
26 import java.util.List;
27 import java.util.stream.Collectors;
28 import java.util.stream.Stream;
29
30 import org.apache.maven.execution.ExecutionEvent;
31 import org.apache.maven.execution.MavenSession;
32 import org.apache.maven.lifecycle.DefaultLifecycles;
33 import org.apache.maven.lifecycle.MissingProjectException;
34 import org.apache.maven.lifecycle.NoGoalSpecifiedException;
35 import org.apache.maven.lifecycle.internal.ExecutionEventCatapult;
36 import org.apache.maven.lifecycle.internal.GoalTask;
37 import org.apache.maven.lifecycle.internal.LifecyclePluginResolver;
38 import org.apache.maven.lifecycle.internal.LifecycleStarter;
39 import org.apache.maven.lifecycle.internal.LifecycleTask;
40 import org.apache.maven.lifecycle.internal.MojoDescriptorCreator;
41 import org.apache.maven.lifecycle.internal.ReactorBuildStatus;
42 import org.apache.maven.lifecycle.internal.ReactorContext;
43 import org.apache.maven.lifecycle.internal.TaskSegment;
44 import org.apache.maven.plugin.descriptor.MojoDescriptor;
45 import org.apache.maven.project.MavenProject;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
48
49 import static java.util.Objects.requireNonNull;
50
51
52
53
54 @Named("concurrent")
55 @Singleton
56 public class ConcurrentLifecycleStarter implements LifecycleStarter {
57 private final Logger logger = LoggerFactory.getLogger(getClass());
58
59 private final ExecutionEventCatapult eventCatapult;
60 private final DefaultLifecycles defaultLifeCycles;
61 private final BuildPlanExecutor executor;
62 private final LifecyclePluginResolver lifecyclePluginResolver;
63 private final MojoDescriptorCreator mojoDescriptorCreator;
64
65 @Inject
66 public ConcurrentLifecycleStarter(
67 ExecutionEventCatapult eventCatapult,
68 DefaultLifecycles defaultLifeCycles,
69 BuildPlanExecutor executor,
70 LifecyclePluginResolver lifecyclePluginResolver,
71 MojoDescriptorCreator mojoDescriptorCreator) {
72 this.eventCatapult = eventCatapult;
73 this.defaultLifeCycles = defaultLifeCycles;
74 this.executor = executor;
75 this.lifecyclePluginResolver = lifecyclePluginResolver;
76 this.mojoDescriptorCreator = mojoDescriptorCreator;
77 }
78
79 public void execute(MavenSession session) {
80 eventCatapult.fire(ExecutionEvent.Type.SessionStarted, session, null);
81
82 try {
83 if (requiresProject(session) && projectIsNotPresent(session)) {
84 throw new MissingProjectException("The goal you specified requires a project to execute"
85 + " but there is no POM in this directory (" + session.getTopDirectory() + ")."
86 + " Please verify you invoked Maven from the correct directory.");
87 }
88
89 List<TaskSegment> taskSegments = calculateTaskSegments(session);
90 if (taskSegments.isEmpty()) {
91 throw new NoGoalSpecifiedException("No goals have been specified for this build."
92 + " You must specify a valid lifecycle phase or a goal in the format <plugin-prefix>:<goal> or"
93 + " <plugin-group-id>:<plugin-artifact-id>[:<plugin-version>]:<goal>."
94 + " Available lifecycle phases are: " + defaultLifeCycles.getLifecyclePhaseList() + ".");
95 }
96
97 int degreeOfConcurrency = session.getRequest().getDegreeOfConcurrency();
98 if (degreeOfConcurrency > 1) {
99 logger.info("");
100 logger.info(String.format(
101 "Using the %s implementation with a thread count of %d",
102 executor.getClass().getSimpleName(), degreeOfConcurrency));
103 }
104
105 ClassLoader oldContextClassLoader = Thread.currentThread().getContextClassLoader();
106 ReactorBuildStatus reactorBuildStatus = new ReactorBuildStatus(session.getProjectDependencyGraph());
107 ReactorContext reactorContext =
108 new ReactorContext(session.getResult(), oldContextClassLoader, reactorBuildStatus);
109 executor.execute(session, reactorContext, taskSegments);
110
111 } catch (Exception e) {
112 session.getResult().addException(e);
113 } finally {
114 eventCatapult.fire(ExecutionEvent.Type.SessionEnded, session, null);
115 }
116 }
117
118 public List<TaskSegment> calculateTaskSegments(MavenSession session) throws Exception {
119
120 MavenProject rootProject = session.getTopLevelProject();
121
122 List<String> tasks = requireNonNull(session.getGoals());
123
124 if (tasks.isEmpty()
125 && (rootProject.getDefaultGoal() != null
126 && !rootProject.getDefaultGoal().isEmpty())) {
127 tasks = Stream.of(rootProject.getDefaultGoal().split("\\s+"))
128 .filter(g -> !g.isEmpty())
129 .collect(Collectors.toList());
130 }
131
132 return calculateTaskSegments(session, tasks);
133 }
134
135 public List<TaskSegment> calculateTaskSegments(MavenSession session, List<String> tasks) throws Exception {
136 List<TaskSegment> taskSegments = new ArrayList<>(tasks.size());
137
138 TaskSegment currentSegment = null;
139
140 for (String task : tasks) {
141 if (isGoalSpecification(task)) {
142
143
144 lifecyclePluginResolver.resolveMissingPluginVersions(session.getTopLevelProject(), session);
145
146 MojoDescriptor mojoDescriptor =
147 mojoDescriptorCreator.getMojoDescriptor(task, session, session.getTopLevelProject());
148
149 boolean aggregating = mojoDescriptor.isAggregator() || !mojoDescriptor.isProjectRequired();
150
151 if (currentSegment == null || currentSegment.isAggregating() != aggregating) {
152 currentSegment = new TaskSegment(aggregating);
153 taskSegments.add(currentSegment);
154 }
155
156 currentSegment.getTasks().add(new GoalTask(task));
157 } else {
158
159
160 if (currentSegment == null || currentSegment.isAggregating()) {
161 currentSegment = new TaskSegment(false);
162 taskSegments.add(currentSegment);
163 }
164
165 currentSegment.getTasks().add(new LifecycleTask(task));
166 }
167 }
168
169 return taskSegments;
170 }
171
172 private boolean projectIsNotPresent(MavenSession session) {
173 return !session.getRequest().isProjectPresent();
174 }
175
176 private boolean requiresProject(MavenSession session) {
177 List<String> goals = session.getGoals();
178 if (goals != null) {
179 for (String goal : goals) {
180 if (!isGoalSpecification(goal)) {
181 return true;
182 }
183 }
184 }
185 return false;
186 }
187
188 private boolean isGoalSpecification(String task) {
189 return task.indexOf(':') >= 0;
190 }
191 }