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;
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.Arrays;
27  import java.util.HashMap;
28  import java.util.LinkedHashMap;
29  import java.util.LinkedHashSet;
30  import java.util.List;
31  import java.util.Map;
32  import java.util.Set;
33  import java.util.stream.Collectors;
34  
35  import org.apache.maven.lifecycle.providers.lifecycle.CleanLifecycleProvider;
36  import org.apache.maven.lifecycle.providers.lifecycle.DefaultLifecycleProvider;
37  import org.apache.maven.lifecycle.providers.lifecycle.SiteLifecycleProvider;
38  import org.codehaus.plexus.PlexusContainer;
39  import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
40  import org.codehaus.plexus.logging.Logger;
41  import org.codehaus.plexus.util.StringUtils;
42  
43  /**
44   * @since 3.0
45   * @author Jason van Zyl
46   * @author Kristian Rosenvold
47   */
48  // TODO The configuration for the lifecycle needs to be externalized so that I can use the annotations properly for the
49  // wiring and reference and external source for the lifecycle configuration.
50  @Singleton
51  @Named
52  public class DefaultLifecycles {
53      private static final List<String> BUILT_IN_LIFECYCLES =
54              Arrays.asList(CleanLifecycleProvider.NAME, DefaultLifecycleProvider.NAME, SiteLifecycleProvider.NAME);
55      private static final boolean SITE_DISABLED = Boolean.getBoolean("maven.site.lifecycle.disabled");
56  
57      /**
58       * @deprecated Use {@link #getStandardLifecycles()} instead.
59       */
60      @Deprecated
61      public static final String[] STANDARD_LIFECYCLES = {
62          CleanLifecycleProvider.NAME, DefaultLifecycleProvider.NAME, SiteLifecycleProvider.NAME
63      };
64  
65      @Inject
66      private Map<String, Lifecycle> lifecycles;
67  
68      @Inject
69      private Logger logger;
70  
71      @Inject
72      private PlexusContainer plexusContainer;
73  
74      public DefaultLifecycles() {}
75  
76      public DefaultLifecycles(Map<String, Lifecycle> lifecycles, Logger logger) {
77          this.lifecycles = lifecycles;
78          this.logger = logger;
79      }
80  
81      private boolean isEnabled(String lifecycleId) {
82          if (SiteLifecycleProvider.NAME.equals(lifecycleId)) {
83              return !SITE_DISABLED;
84          } else {
85              return true;
86          }
87      }
88  
89      public List<String> getStandardLifecycles() {
90          return BUILT_IN_LIFECYCLES.stream().filter(this::isEnabled).collect(Collectors.toList());
91      }
92  
93      public Lifecycle get(String key) {
94          return getPhaseToLifecycleMap().get(key);
95      }
96  
97      /**
98       * We use this to map all phases to the lifecycle that contains it. This is used so that a user can specify the
99       * phase they want to execute and we can easily determine what lifecycle we need to run.
100      *
101      * @return A map of lifecycles, indexed on id
102      */
103     public Map<String, Lifecycle> getPhaseToLifecycleMap() {
104         // If people are going to make their own lifecycles then we need to tell people how to namespace them correctly
105         // so that they don't interfere with internally defined lifecycles.
106 
107         HashMap<String, Lifecycle> phaseToLifecycleMap = new HashMap<>();
108 
109         for (Lifecycle lifecycle : getLifeCycles()) {
110             if (logger.isDebugEnabled()) {
111                 logger.debug("Lifecycle " + lifecycle);
112             }
113 
114             for (String phase : lifecycle.getPhases()) {
115                 // The first definition wins.
116                 if (!phaseToLifecycleMap.containsKey(phase)) {
117                     phaseToLifecycleMap.put(phase, lifecycle);
118                 } else {
119                     Lifecycle original = phaseToLifecycleMap.get(phase);
120                     logger.warn("Duplicated lifecycle phase " + phase + ". Defined in " + original.getId()
121                             + " but also in " + lifecycle.getId());
122                 }
123             }
124         }
125 
126         return phaseToLifecycleMap;
127     }
128 
129     /**
130      * Returns an ordered list of lifecycles
131      */
132     public List<Lifecycle> getLifeCycles() {
133         // ensure canonical order of standard lifecycles
134 
135         Map<String, Lifecycle> lifecycles = new LinkedHashMap<>();
136 
137         // filter by visibility (plexus vs sisu diff; "realms" are plexus thing)
138         // in some tests container is not injected
139         if (this.plexusContainer != null) {
140             for (String name : this.lifecycles.keySet()) {
141                 if (!isEnabled(name)) {
142                     continue;
143                 }
144                 try {
145                     lifecycles.put(name, plexusContainer.lookup(Lifecycle.class, name));
146                 } catch (ComponentLookupException e) {
147                     // skip it
148                 }
149             }
150         } else {
151             lifecycles.putAll(this.lifecycles);
152         }
153 
154         LinkedHashSet<String> lifecycleNames = new LinkedHashSet<>(getStandardLifecycles());
155         lifecycleNames.addAll(lifecycles.keySet());
156 
157         ArrayList<Lifecycle> result = new ArrayList<>();
158         for (String name : lifecycleNames) {
159             Lifecycle lifecycle = lifecycles.get(name);
160             if (lifecycle.getId() == null) {
161                 throw new NullPointerException("A lifecycle must have an id.");
162             }
163             result.add(lifecycle);
164         }
165 
166         return result;
167     }
168 
169     public String getLifecyclePhaseList() {
170         Set<String> phases = new LinkedHashSet<>();
171 
172         for (Lifecycle lifecycle : getLifeCycles()) {
173             phases.addAll(lifecycle.getPhases());
174         }
175 
176         return StringUtils.join(phases.iterator(), ", ");
177     }
178 }