View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.lifecycle.internal;
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.api.Lifecycle;
31  import org.apache.maven.execution.MavenSession;
32  import org.apache.maven.lifecycle.LifecycleNotFoundException;
33  import org.apache.maven.lifecycle.LifecyclePhaseNotFoundException;
34  import org.apache.maven.plugin.InvalidPluginDescriptorException;
35  import org.apache.maven.plugin.MojoNotFoundException;
36  import org.apache.maven.plugin.PluginDescriptorParsingException;
37  import org.apache.maven.plugin.PluginNotFoundException;
38  import org.apache.maven.plugin.PluginResolutionException;
39  import org.apache.maven.plugin.descriptor.MojoDescriptor;
40  import org.apache.maven.plugin.prefix.NoPluginFoundForPrefixException;
41  import org.apache.maven.plugin.version.PluginVersionResolutionException;
42  import org.apache.maven.project.MavenProject;
43  import org.slf4j.Logger;
44  import org.slf4j.LoggerFactory;
45  
46  import static java.util.Objects.requireNonNull;
47  
48  /**
49   * <p>
50   * Calculates the task segments in the build
51   * </p>
52   * <strong>NOTE:</strong> This class is not part of any public api and can be changed or deleted without prior notice.
53   *
54   * @since 3.0
55   */
56  @Named
57  @Singleton
58  public class DefaultLifecycleTaskSegmentCalculator implements LifecycleTaskSegmentCalculator {
59      private static final Logger LOGGER = LoggerFactory.getLogger(DefaultLifecycleTaskSegmentCalculator.class);
60  
61      private final MojoDescriptorCreator mojoDescriptorCreator;
62  
63      private final LifecyclePluginResolver lifecyclePluginResolver;
64  
65      @Inject
66      public DefaultLifecycleTaskSegmentCalculator(
67              MojoDescriptorCreator mojoDescriptorCreator, LifecyclePluginResolver lifecyclePluginResolver) {
68          this.mojoDescriptorCreator = mojoDescriptorCreator;
69          this.lifecyclePluginResolver = lifecyclePluginResolver;
70      }
71  
72      @Override
73      public List<TaskSegment> calculateTaskSegments(MavenSession session)
74              throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
75                      MojoNotFoundException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
76                      PluginVersionResolutionException, LifecyclePhaseNotFoundException, LifecycleNotFoundException {
77  
78          MavenProject rootProject = session.getTopLevelProject();
79  
80          List<String> tasks = requireNonNull(session.getGoals()); // session never returns null, but empty list
81  
82          if (tasks.isEmpty()
83                  && (rootProject.getDefaultGoal() != null
84                          && !rootProject.getDefaultGoal().isEmpty())) {
85              tasks = Stream.of(rootProject.getDefaultGoal().split("\\s+"))
86                      .filter(g -> !g.isEmpty())
87                      .collect(Collectors.toList());
88          }
89  
90          return calculateTaskSegments(session, tasks);
91      }
92  
93      @Override
94      public List<TaskSegment> calculateTaskSegments(MavenSession session, List<String> tasks)
95              throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
96                      MojoNotFoundException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
97                      PluginVersionResolutionException {
98          List<TaskSegment> taskSegments = new ArrayList<>(tasks.size());
99  
100         TaskSegment currentSegment = null;
101 
102         for (String task : tasks) {
103             if (isBeforeOrAfterPhase(task)) {
104                 String prevTask = task;
105                 task = PhaseId.of(task).phase();
106                 LOGGER.warn("Illegal call to phase '{}'. The main phase '{}' will be used instead.", prevTask, task);
107             }
108             if (isGoalSpecification(task)) {
109                 // "pluginPrefix[:version]:goal" or "groupId:artifactId[:version]:goal"
110 
111                 lifecyclePluginResolver.resolveMissingPluginVersions(session.getTopLevelProject(), session);
112 
113                 MojoDescriptor mojoDescriptor =
114                         mojoDescriptorCreator.getMojoDescriptor(task, session, session.getTopLevelProject());
115 
116                 boolean aggregating = mojoDescriptor.isAggregator() || !mojoDescriptor.isProjectRequired();
117 
118                 if (currentSegment == null || currentSegment.isAggregating() != aggregating) {
119                     currentSegment = new TaskSegment(aggregating);
120                     taskSegments.add(currentSegment);
121                 }
122 
123                 currentSegment.getTasks().add(new GoalTask(task));
124             } else {
125                 // lifecycle phase
126 
127                 if (currentSegment == null || currentSegment.isAggregating()) {
128                     currentSegment = new TaskSegment(false);
129                     taskSegments.add(currentSegment);
130                 }
131 
132                 currentSegment.getTasks().add(new LifecycleTask(task));
133             }
134         }
135 
136         return taskSegments;
137     }
138 
139     @Override
140     public boolean requiresProject(MavenSession session) {
141         List<String> goals = session.getGoals();
142         if (goals != null) {
143             for (String goal : goals) {
144                 if (!isGoalSpecification(goal)) {
145                     return true;
146                 }
147             }
148         }
149         return false;
150     }
151 
152     private boolean isBeforeOrAfterPhase(String task) {
153         return task.startsWith(Lifecycle.BEFORE) || task.startsWith(Lifecycle.AFTER);
154     }
155 
156     private boolean isGoalSpecification(String task) {
157         return task.indexOf(':') >= 0;
158     }
159 }