View Javadoc
1   package org.apache.maven.plugins.invoker;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.File;
23  import java.io.FileNotFoundException;
24  import java.io.IOException;
25  import java.io.InputStream;
26  import java.net.MalformedURLException;
27  import java.net.URL;
28  import java.util.ArrayList;
29  import java.util.Arrays;
30  import java.util.Collection;
31  import java.util.Iterator;
32  import java.util.List;
33  import java.util.Properties;
34  import java.util.stream.Collectors;
35  
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  import org.codehaus.plexus.util.StringUtils;
42  
43  /**
44   * Provides utility methods for selecting build jobs based on environmental conditions.
45   *
46   * @author Benjamin Bentmann
47   */
48  class SelectorUtils
49  {
50  
51      static void parseList( String list, Collection<String> includes, Collection<String> excludes )
52      {
53          String[] tokens = ( list != null ) ? StringUtils.split( list, "," ) : new String[0];
54  
55          for ( String token1 : tokens )
56          {
57              String token = token1.trim();
58  
59              if ( token.startsWith( "!" ) )
60              {
61                  excludes.add( token.substring( 1 ) );
62              }
63              else
64              {
65                  includes.add( token );
66              }
67          }
68      }
69  
70      static boolean isOsFamily( String osSpec )
71      {
72          List<String> includes = new ArrayList<>();
73          List<String> excludes = new ArrayList<>();
74          parseList( osSpec, includes, excludes );
75  
76          return isOsFamily( includes, true ) && !isOsFamily( excludes, false );
77      }
78  
79      static boolean isOsFamily( List<String> families, boolean defaultMatch )
80      {
81          if ( families != null && !families.isEmpty() )
82          {
83              for ( String family : families )
84              {
85                  if ( Os.isFamily( family ) )
86                  {
87                      return true;
88                  }
89              }
90  
91              return false;
92          }
93          else
94          {
95              return defaultMatch;
96          }
97      }
98  
99      /**
100      * Retrieves the current Maven version.
101      *
102      * @return The current Maven version.
103      */
104     static String getMavenVersion()
105     {
106         try
107         {
108             // This relies on the fact that MavenProject is the in core classloader
109             // and that the core classloader is for the maven-core artifact
110             // and that should have a pom.properties file
111             // if this ever changes, we will have to revisit this code.
112             Properties properties = new Properties();
113             // CHECKSTYLE_OFF: LineLength
114             properties.load( MavenProject.class.getClassLoader()
115                                  .getResourceAsStream( "META-INF/maven/org.apache.maven/maven-core/pom.properties" ) );
116             // CHECKSTYLE_ON: LineLength
117             return StringUtils.trim( properties.getProperty( "version" ) );
118         }
119         catch ( Exception e )
120         {
121             return null;
122         }
123     }
124 
125     static String getMavenVersion( File mavenHome ) throws IOException
126     {
127         File mavenLib = new File( mavenHome, "lib" );
128         File[] jarFiles = mavenLib.listFiles( ( dir, name ) -> name.endsWith( ".jar" ) );
129 
130         if ( jarFiles == null )
131         {
132             throw new IllegalArgumentException( "Invalid Maven home installation directory: " + mavenHome );
133         }
134 
135         for ( File file : jarFiles )
136         {
137             try
138             {
139                 URL url = new URL( "jar:" + file.toURI().toURL().toExternalForm()
140                                  + "!/META-INF/maven/org.apache.maven/maven-core/pom.properties" );
141 
142                 try ( InputStream in = url.openStream() )
143                 {
144                     Properties properties = new Properties();
145                     properties.load( in );
146                     String version = StringUtils.trim( properties.getProperty( "version" ) );
147                     if ( version != null )
148                     {
149                         return version;
150                     }
151                 }
152             }
153             catch ( FileNotFoundException | MalformedURLException e )
154             {
155                 // ignore
156             }
157         }
158         return null;
159     }
160 
161     static boolean isMavenVersion( String mavenSpec )
162     {
163         return isMavenVersion( mavenSpec, getMavenVersion() );
164     }
165 
166     static boolean isMavenVersion( String mavenSpec, String actualVersion )
167     {
168         List<String> includes = new ArrayList<>();
169         List<String> excludes = new ArrayList<>();
170         parseList( mavenSpec, includes, excludes );
171 
172         List<Integer> mavenVersionList = parseVersion( actualVersion );
173 
174         return isJreVersion( mavenVersionList, includes, true ) && !isJreVersion( mavenVersionList, excludes, false );
175     }
176 
177     static String getJreVersion()
178     {
179         return System.getProperty( "java.version", "" );
180     }
181 
182     static String getJreVersion( File javaHome )
183     {
184         // @todo detect actual version
185         return null;
186     }
187 
188     static boolean isJreVersion( String jreSpec )
189     {
190         return isJreVersion( jreSpec, getJreVersion() );
191     }
192 
193     static boolean isJreVersion( String jreSpec, String actualJreVersion )
194     {
195         List<String> includes = new ArrayList<>();
196         List<String> excludes = new ArrayList<>();
197         parseList( jreSpec, includes, excludes );
198 
199         List<Integer> jreVersion = parseVersion( actualJreVersion );
200 
201         return isJreVersion( jreVersion, includes, true ) && !isJreVersion( jreVersion, excludes, false );
202     }
203 
204     static boolean isJreVersion( List<Integer> jreVersion, List<String> versionPatterns, boolean defaultMatch )
205     {
206         if ( versionPatterns != null && !versionPatterns.isEmpty() )
207         {
208             for ( String versionPattern : versionPatterns )
209             {
210                 if ( isJreVersion( jreVersion, versionPattern ) )
211                 {
212                     return true;
213                 }
214             }
215 
216             return false;
217         }
218         else
219         {
220             return defaultMatch;
221         }
222     }
223 
224     static boolean isJreVersion( List<Integer> jreVersion, String versionPattern )
225     {
226         List<Integer> checkVersion = parseVersion( versionPattern );
227 
228         if ( versionPattern.endsWith( "+" ) )
229         {
230             // 1.5+ <=> [1.5,)
231             return compareVersions( jreVersion, checkVersion ) >= 0;
232         }
233         else if ( versionPattern.endsWith( "-" ) )
234         {
235             // 1.5- <=> (,1.5)
236             return compareVersions( jreVersion, checkVersion ) < 0;
237         }
238         else
239         {
240             // 1.5 <=> [1.5,1.6)
241             return checkVersion.size() <= jreVersion.size()
242                 && checkVersion.equals( jreVersion.subList( 0, checkVersion.size() ) );
243         }
244     }
245 
246     static List<Integer> parseVersion( String version )
247     {
248         version = version.replaceAll( "[^0-9]", "." );
249 
250         String[] tokens = StringUtils.split( version, "." );
251 
252         List<Integer> numbers = Arrays.stream( tokens ).map( Integer::valueOf ).collect( Collectors.toList() );
253 
254         return numbers;
255     }
256 
257     static int compareVersions( List<Integer> version1, List<Integer> version2 )
258     {
259         for ( Iterator<Integer> it1 = version1.iterator(), it2 = version2.iterator(); ; )
260         {
261             if ( !it1.hasNext() )
262             {
263                 return it2.hasNext() ? -1 : 0;
264             }
265             if ( !it2.hasNext() )
266             {
267                 return it1.hasNext() ? 1 : 0;
268             }
269 
270             Integer num1 = it1.next();
271             Integer num2 = it2.next();
272 
273             int rel = num1.compareTo( num2 );
274             if ( rel != 0 )
275             {
276                 return rel;
277             }
278         }
279     }
280 
281     /**
282      * @param toolchainPrivateManager
283      * @param invokerToolchains
284      * @return {@code true} if all invokerToolchains are available, otherwise {@code false}
285      */
286     static boolean isToolchain( ToolchainPrivateManager toolchainPrivateManager,
287                                 Collection<InvokerToolchain> invokerToolchains )
288     {
289         for ( InvokerToolchain invokerToolchain : invokerToolchains )
290         {
291             boolean found = false;
292             try
293             {
294                 for ( ToolchainPrivate tc : toolchainPrivateManager.getToolchainPrivates( invokerToolchain.getType() ) )
295                 {
296                     if ( !invokerToolchain.getType().equals( tc.getType() ) )
297                     {
298                         // useful because of MNG-5716
299                         continue;
300                     }
301 
302                     if ( tc.matchesRequirements( invokerToolchain.getProvides() ) )
303                     {
304                         found = true;
305                         continue;
306                     }
307                 }
308             }
309             catch ( MisconfiguredToolchainException e )
310             {
311                 return false;
312             }
313 
314             if ( !found )
315             {
316                 return false;
317             }
318         }
319 
320         return true;
321     }
322 }