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.plugins.toolchain;
20  
21  import java.util.ArrayList;
22  import java.util.List;
23  import java.util.Map;
24  
25  import org.apache.maven.execution.MavenSession;
26  import org.apache.maven.plugin.AbstractMojo;
27  import org.apache.maven.plugin.MojoExecutionException;
28  import org.apache.maven.plugin.MojoFailureException;
29  import org.apache.maven.plugins.annotations.Component;
30  import org.apache.maven.plugins.annotations.LifecyclePhase;
31  import org.apache.maven.plugins.annotations.Mojo;
32  import org.apache.maven.plugins.annotations.Parameter;
33  import org.apache.maven.toolchain.MisconfiguredToolchainException;
34  import org.apache.maven.toolchain.ToolchainManagerPrivate;
35  import org.apache.maven.toolchain.ToolchainPrivate;
36  
37  /**
38   * Check that toolchains requirements are met by currently configured toolchains in {@code toolchains.xml} and
39   * store the selected toolchain in build context for later retrieval by other plugins.
40   *
41   * @author mkleint
42   */
43  @Mojo(
44          name = "toolchain",
45          defaultPhase = LifecyclePhase.VALIDATE,
46          configurator = "toolchains-requirement-configurator",
47          threadSafe = true)
48  public class ToolchainMojo extends AbstractMojo {
49      private static final Object LOCK = new Object();
50  
51      /**
52       */
53      @Component
54      private ToolchainManagerPrivate toolchainManagerPrivate;
55  
56      /**
57       * The current build session instance. This is used for toolchain manager API calls.
58       */
59      @Parameter(defaultValue = "${session}", readonly = true, required = true)
60      private MavenSession session;
61  
62      /**
63       * Toolchains requirements, specified by one
64       * <pre>{@code   <toolchain-type>
65       *     <param>expected value</param>
66       *     ...
67       *   </toolchain-type>}</pre>
68       * element for each required toolchain.
69       */
70      @Parameter(required = true)
71      private ToolchainsRequirement toolchains;
72  
73      @Override
74      public void execute() throws MojoExecutionException, MojoFailureException {
75          if (toolchains == null) {
76              // should not happen since parameter is required...
77              getLog().warn("No toolchains requirements configured.");
78              return;
79          }
80  
81          List<String> nonMatchedTypes = new ArrayList<>();
82  
83          for (Map.Entry<String, Map<String, String>> entry :
84                  toolchains.getToolchains().entrySet()) {
85              String type = entry.getKey();
86  
87              if (!selectToolchain(type, entry.getValue())) {
88                  nonMatchedTypes.add(type);
89              }
90          }
91  
92          if (!nonMatchedTypes.isEmpty()) {
93              // TODO add the default toolchain instance if defined??
94              StringBuilder buff = new StringBuilder();
95              buff.append("Cannot find matching toolchain definitions for the following toolchain types:");
96  
97              for (String type : nonMatchedTypes) {
98                  buff.append(System.lineSeparator());
99                  buff.append(getToolchainRequirementAsString(type, toolchains.getParams(type)));
100             }
101 
102             getLog().error(buff.toString());
103 
104             throw new MojoFailureException(buff.toString() + System.lineSeparator()
105                     + "Please make sure you define the required toolchains in your ~/.m2/toolchains.xml file.");
106         }
107     }
108 
109     protected String getToolchainRequirementAsString(String type, Map<String, String> params) {
110         StringBuilder buff = new StringBuilder();
111 
112         buff.append(type).append(" [");
113 
114         if (params.size() == 0) {
115             buff.append(" any");
116         } else {
117             for (Map.Entry<String, String> param : params.entrySet()) {
118                 buff.append(" ").append(param.getKey()).append("='").append(param.getValue());
119                 buff.append("'");
120             }
121         }
122 
123         buff.append(" ]");
124 
125         return buff.toString();
126     }
127 
128     protected boolean selectToolchain(String type, Map<String, String> params) throws MojoExecutionException {
129         getLog().info("Required toolchain: " + getToolchainRequirementAsString(type, params));
130         int typeFound = 0;
131 
132         try {
133             ToolchainPrivate[] tcs = getToolchains(type);
134 
135             for (ToolchainPrivate tc : tcs) {
136                 if (!type.equals(tc.getType())) {
137                     // useful because of MNG-5716
138                     continue;
139                 }
140 
141                 typeFound++;
142 
143                 if (tc.matchesRequirements(params)) {
144                     getLog().info("Found matching toolchain for type " + type + ": " + tc);
145 
146                     // store matching toolchain to build context
147                     synchronized (LOCK) {
148                         toolchainManagerPrivate.storeToolchainToBuildContext(tc, session);
149                     }
150 
151                     return true;
152                 }
153             }
154         } catch (MisconfiguredToolchainException ex) {
155             throw new MojoExecutionException("Misconfigured toolchains.", ex);
156         }
157 
158         getLog().error("No toolchain " + ((typeFound == 0) ? "found" : ("matched from " + typeFound + " found"))
159                 + " for type " + type);
160 
161         return false;
162     }
163 
164     private ToolchainPrivate[] getToolchains(String type)
165             throws MojoExecutionException, MisconfiguredToolchainException {
166         return toolchainManagerPrivate.getToolchainsForType(type, session);
167     }
168 }