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.invoker;
20  
21  import java.io.File;
22  import java.io.FileNotFoundException;
23  import java.io.IOException;
24  import java.io.InputStream;
25  import java.net.MalformedURLException;
26  import java.net.URL;
27  import java.util.ArrayList;
28  import java.util.Arrays;
29  import java.util.Collection;
30  import java.util.Iterator;
31  import java.util.List;
32  import java.util.Properties;
33  import java.util.stream.Collectors;
34  
35  import org.apache.commons.lang3.StringUtils;
36  import org.apache.maven.plugins.invoker.AbstractInvokerMojo.ToolchainPrivateManager;
37  import org.apache.maven.project.MavenProject;
38  import org.apache.maven.toolchain.MisconfiguredToolchainException;
39  import org.apache.maven.toolchain.ToolchainPrivate;
40  import org.codehaus.plexus.util.Os;
41  
42  /**
43   * Provides utility methods for selecting build jobs based on environmental conditions.
44   *
45   * @author Benjamin Bentmann
46   */
47  class SelectorUtils {
48  
49      static void parseList(String list, Collection<String> includes, Collection<String> excludes) {
50          String[] tokens = (list != null) ? StringUtils.split(list, ",") : new String[0];
51  
52          for (String token1 : tokens) {
53              String token = token1.trim();
54  
55              if (token.startsWith("!")) {
56                  excludes.add(token.substring(1));
57              } else {
58                  includes.add(token);
59              }
60          }
61      }
62  
63      static boolean isOsFamily(String osSpec) {
64          List<String> includes = new ArrayList<>();
65          List<String> excludes = new ArrayList<>();
66          parseList(osSpec, includes, excludes);
67  
68          return isOsFamily(includes, true) && !isOsFamily(excludes, false);
69      }
70  
71      static boolean isOsFamily(List<String> families, boolean defaultMatch) {
72          if (families != null && !families.isEmpty()) {
73              for (String family : families) {
74                  if (Os.isFamily(family)) {
75                      return true;
76                  }
77              }
78  
79              return false;
80          } else {
81              return defaultMatch;
82          }
83      }
84  
85      /**
86       * Retrieves the current Maven version.
87       *
88       * @return The current Maven version.
89       */
90      static String getMavenVersion() {
91          try {
92              // This relies on the fact that MavenProject is the in core classloader
93              // and that the core classloader is for the maven-core artifact
94              // and that should have a pom.properties file
95              // if this ever changes, we will have to revisit this code.
96              Properties properties = new Properties();
97              // CHECKSTYLE_OFF: LineLength
98              properties.load(MavenProject.class
99                      .getClassLoader()
100                     .getResourceAsStream("META-INF/maven/org.apache.maven/maven-core/pom.properties"));
101             // CHECKSTYLE_ON: LineLength
102             return StringUtils.trim(properties.getProperty("version"));
103         } catch (Exception e) {
104             return null;
105         }
106     }
107 
108     static String getMavenVersion(File mavenHome) throws IOException {
109         File mavenLib = new File(mavenHome, "lib");
110         File[] jarFiles = mavenLib.listFiles((dir, name) -> name.endsWith(".jar"));
111 
112         if (jarFiles == null) {
113             throw new IllegalArgumentException("Invalid Maven home installation directory: " + mavenHome);
114         }
115 
116         for (File file : jarFiles) {
117             try {
118                 URL url = new URL("jar:" + file.toURI().toURL().toExternalForm()
119                         + "!/META-INF/maven/org.apache.maven/maven-core/pom.properties");
120 
121                 try (InputStream in = url.openStream()) {
122                     Properties properties = new Properties();
123                     properties.load(in);
124                     String version = StringUtils.trim(properties.getProperty("version"));
125                     if (version != null) {
126                         return version;
127                     }
128                 }
129             } catch (FileNotFoundException | MalformedURLException e) {
130                 // ignore
131             }
132         }
133         return null;
134     }
135 
136     static boolean isMavenVersion(String mavenSpec) {
137         return isMavenVersion(mavenSpec, getMavenVersion());
138     }
139 
140     static boolean isMavenVersion(String mavenSpec, String actualVersion) {
141         List<String> includes = new ArrayList<>();
142         List<String> excludes = new ArrayList<>();
143         parseList(mavenSpec, includes, excludes);
144 
145         List<Integer> mavenVersionList = parseVersion(actualVersion);
146 
147         return isJreVersion(mavenVersionList, includes, true) && !isJreVersion(mavenVersionList, excludes, false);
148     }
149 
150     static String getJreVersion() {
151         return System.getProperty("java.version", "");
152     }
153 
154     static String getJreVersion(File javaHome) {
155         // @todo detect actual version
156         return null;
157     }
158 
159     static boolean isJreVersion(String jreSpec) {
160         return isJreVersion(jreSpec, getJreVersion());
161     }
162 
163     static boolean isJreVersion(String jreSpec, String actualJreVersion) {
164         List<String> includes = new ArrayList<>();
165         List<String> excludes = new ArrayList<>();
166         parseList(jreSpec, includes, excludes);
167 
168         List<Integer> jreVersion = parseVersion(actualJreVersion);
169 
170         return isJreVersion(jreVersion, includes, true) && !isJreVersion(jreVersion, excludes, false);
171     }
172 
173     static boolean isJreVersion(List<Integer> jreVersion, List<String> versionPatterns, boolean defaultMatch) {
174         if (versionPatterns != null && !versionPatterns.isEmpty()) {
175             for (String versionPattern : versionPatterns) {
176                 if (isJreVersion(jreVersion, versionPattern)) {
177                     return true;
178                 }
179             }
180 
181             return false;
182         } else {
183             return defaultMatch;
184         }
185     }
186 
187     static boolean isJreVersion(List<Integer> jreVersion, String versionPattern) {
188         List<Integer> checkVersion = parseVersion(versionPattern);
189 
190         if (versionPattern.endsWith("+")) {
191             // 1.5+ <=> [1.5,)
192             return compareVersions(jreVersion, checkVersion) >= 0;
193         } else if (versionPattern.endsWith("-")) {
194             // 1.5- <=> (,1.5)
195             return compareVersions(jreVersion, checkVersion) < 0;
196         } else {
197             // 1.5 <=> [1.5,1.6)
198             return checkVersion.size() <= jreVersion.size()
199                     && checkVersion.equals(jreVersion.subList(0, checkVersion.size()));
200         }
201     }
202 
203     static List<Integer> parseVersion(String version) {
204         version = version.replaceAll("[^0-9]", ".");
205 
206         String[] tokens = StringUtils.split(version, ".");
207 
208         List<Integer> numbers = Arrays.stream(tokens).map(Integer::valueOf).collect(Collectors.toList());
209 
210         return numbers;
211     }
212 
213     static int compareVersions(List<Integer> version1, List<Integer> version2) {
214         for (Iterator<Integer> it1 = version1.iterator(), it2 = version2.iterator(); ; ) {
215             if (!it1.hasNext()) {
216                 return it2.hasNext() ? -1 : 0;
217             }
218             if (!it2.hasNext()) {
219                 return it1.hasNext() ? 1 : 0;
220             }
221 
222             Integer num1 = it1.next();
223             Integer num2 = it2.next();
224 
225             int rel = num1.compareTo(num2);
226             if (rel != 0) {
227                 return rel;
228             }
229         }
230     }
231 
232     /**
233      * @param toolchainPrivateManager
234      * @param invokerToolchains
235      * @return {@code true} if all invokerToolchains are available, otherwise {@code false}
236      */
237     static boolean isToolchain(
238             ToolchainPrivateManager toolchainPrivateManager, Collection<InvokerToolchain> invokerToolchains) {
239         for (InvokerToolchain invokerToolchain : invokerToolchains) {
240             boolean found = false;
241             try {
242                 for (ToolchainPrivate tc : toolchainPrivateManager.getToolchainPrivates(invokerToolchain.getType())) {
243                     if (!invokerToolchain.getType().equals(tc.getType())) {
244                         // useful because of MNG-5716
245                         continue;
246                     }
247 
248                     if (tc.matchesRequirements(invokerToolchain.getProvides())) {
249                         found = true;
250                         continue;
251                     }
252                 }
253             } catch (MisconfiguredToolchainException e) {
254                 return false;
255             }
256 
257             if (!found) {
258                 return false;
259             }
260         }
261 
262         return true;
263     }
264 }