View Javadoc
1   package org.apache.maven.plugins.enforcer;
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.util.Iterator;
23  
24  import org.apache.maven.enforcer.rule.api.EnforcerRule;
25  import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
26  import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
27  import org.apache.maven.model.Activation;
28  import org.apache.maven.model.ActivationOS;
29  import org.apache.maven.model.Profile;
30  import org.apache.maven.plugin.logging.Log;
31  import org.apache.maven.profiles.activation.OperatingSystemProfileActivator;
32  import org.codehaus.plexus.util.Os;
33  import org.codehaus.plexus.util.StringUtils;
34  
35  /**
36   * This rule checks that the OS is allowed by combinations of family, name, version and cpu architecture. The behavior
37   * is exactly the same as the Maven Os profile activation so the same values are allowed here.
38   *
39   * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
40   * @version $Id: RequireOS.java 1802595 2017-07-21 13:39:48Z rfscholte $
41   */
42  public class RequireOS
43      extends AbstractStandardEnforcerRule
44  {
45  
46      /**
47       * The OS family type desired<br />
48       * Possible values:
49       * <ul>
50       * <li>dos</li>
51       * <li>mac</li>
52       * <li>netware</li>
53       * <li>os/2</li>
54       * <li>tandem</li>
55       * <li>unix</li>
56       * <li>windows</li>
57       * <li>win9x</li>
58       * <li>z/os</li>
59       * <li>os/400</li>
60       * </ul>
61       * 
62       * @see {@link #setFamily(String)}
63       * @see {@link #getFamily()}
64       */
65      private String family = null;
66  
67      /**
68       * The OS name desired.
69       *
70       * @see {@link #setName(String)}
71       * @see {@link #getName()}
72       */
73      private String name = null;
74  
75      /**
76       * The OS version desired.
77       * 
78       * @see {@link #setVersion(String)}
79       * @see {@link #getVersion()}
80       */
81      private String version = null;
82  
83      /**
84       * The OS architecture desired.
85       * 
86       * @see {@link #setArch(String)}
87       * @see {@link #getArch()}
88       */
89      private String arch = null;
90  
91      /**
92       * Display detected OS information.
93       * 
94       * @see {@link #setDisplay(boolean)}
95       * @see {@link #isDisplay()}
96       */
97      private boolean display = false;
98  
99      /**
100      * Instantiates a new RequireOS.
101      */
102     public RequireOS()
103     {
104 
105     }
106 
107     @Override
108     public void execute( EnforcerRuleHelper helper )
109         throws EnforcerRuleException
110     {
111 
112         displayOSInfo( helper.getLog(), display );
113 
114         if ( allParamsEmpty() )
115         {
116             throw new EnforcerRuleException( "All parameters can not be empty. "
117                 + "You must pick at least one of (family, name, version, arch) "
118                 + "or use -Denforcer.os.display=true to see the current OS information." );
119         }
120 
121         if ( isValidFamily( this.family ) )
122         {
123             if ( !isAllowed() )
124             {
125                 String message = getMessage();
126                 if ( StringUtils.isEmpty( message ) )
127                 {
128                     //@formatter:off
129                     message =
130                         ( "OS Arch: " 
131                             + Os.OS_ARCH + " Family: " 
132                             + Os.OS_FAMILY + " Name: " 
133                             + Os.OS_NAME + " Version: "
134                             + Os.OS_VERSION + " is not allowed by" + ( arch != null ? " Arch=" + arch : "" )
135                             + ( family != null ? " Family=" + family : "" ) 
136                             + ( name != null ? " Name=" + name : "" ) 
137                             + ( version != null ? " Version=" + version : "" ) );
138                     //@formatter:on
139                 }
140                 throw new EnforcerRuleException( message );
141             }
142         }
143         else
144         {
145             final int minimumBufferSize = 50;
146             StringBuilder buffer = new StringBuilder( minimumBufferSize );
147             Iterator<?> iter = Os.getValidFamilies().iterator();
148             while ( iter.hasNext() )
149             {
150                 buffer.append( iter.next() );
151                 buffer.append( ", " );
152             }
153             String help = StringUtils.stripEnd( buffer.toString().trim(), "." );
154             throw new EnforcerRuleException( "Invalid Family type used. Valid family types are: " + help );
155         }
156     }
157 
158     /**
159      * Log the current OS information.
160      *
161      * @param log the log
162      * @param info the info
163      */
164     public void displayOSInfo( Log log, boolean info )
165     {
166         String string =
167             "OS Info: Arch: " + Os.OS_ARCH + " Family: " + Os.OS_FAMILY + " Name: " + Os.OS_NAME + " Version: "
168                 + Os.OS_VERSION;
169 
170         if ( !info )
171         {
172             log.debug( string );
173         }
174         else
175         {
176             log.info( string );
177         }
178     }
179 
180     /**
181      * Helper method to determine if the current OS is allowed based on the injected values for family, name, version
182      * and arch.
183      *
184      * @return true if the version is allowed.
185      */
186     public boolean isAllowed()
187     {
188         OperatingSystemProfileActivator activator = new OperatingSystemProfileActivator();
189 
190         return activator.isActive( createProfile() );
191     }
192 
193     /**
194      * Helper method to check that at least one of family, name, version or arch is set.
195      *
196      * @return true if all parameters are empty.
197      */
198     public boolean allParamsEmpty()
199     {
200         // CHECKSTYLE_OFF: LineLength
201         return ( StringUtils.isEmpty( family ) && StringUtils.isEmpty( arch ) && StringUtils.isEmpty( name ) && StringUtils.isEmpty( version ) );
202         // CHECKSTYLE_ON: LineLength
203     }
204 
205     /**
206      * Creates a Profile object that contains the activation information.
207      *
208      * @return a properly populated profile to be used for OS validation.
209      */
210     private Profile createProfile()
211     {
212         Profile profile = new Profile();
213         profile.setActivation( createActivation() );
214         return profile;
215     }
216 
217     /**
218      * Creates an Activation object that contains the ActivationOS information.
219      *
220      * @return a properly populated Activation object.
221      */
222     private Activation createActivation()
223     {
224         Activation activation = new Activation();
225         activation.setActiveByDefault( false );
226         activation.setOs( createOsBean() );
227         return activation;
228     }
229 
230     /**
231      * Creates an ActivationOS object containing family, name, version and arch.
232      *
233      * @return a properly populated ActivationOS object.
234      */
235     private ActivationOS createOsBean()
236     {
237         ActivationOS os = new ActivationOS();
238 
239         os.setArch( arch );
240         os.setFamily( family );
241         os.setName( name );
242         os.setVersion( version );
243 
244         return os;
245     }
246 
247     /**
248      * Helper method to check if the given family is in the following list:
249      * <ul>
250      * <li>dos</li>
251      * <li>mac</li>
252      * <li>netware</li>
253      * <li>os/2</li>
254      * <li>tandem</li>
255      * <li>unix</li>
256      * <li>windows</li>
257      * <li>win9x</li>
258      * <li>z/os</li>
259      * <li>os/400</li>
260      * </ul>
261      * Note: '!' is allowed at the beginning of the string and still considered valid.
262      *
263      * @param theFamily the family to check.
264      * @return true if one of the valid families.
265      */
266     public boolean isValidFamily( String theFamily )
267     {
268 
269         // in case they are checking !family
270         theFamily = StringUtils.stripStart( theFamily, "!" );
271 
272         return ( StringUtils.isEmpty( theFamily ) || Os.getValidFamilies().contains( theFamily ) );
273     }
274 
275     /**
276      * Gets the arch.
277      *
278      * @return the arch
279      */
280     public String getArch()
281     {
282         return this.arch;
283     }
284 
285     /**
286      * Sets the arch.
287      *
288      * @param theArch the arch to set
289      */
290     public void setArch( String theArch )
291     {
292         this.arch = theArch;
293     }
294 
295     /**
296      * Gets the family.
297      *
298      * @return the family
299      */
300     public String getFamily()
301     {
302         return this.family;
303     }
304 
305     /**
306      * Sets the family.
307      *
308      * @param theFamily the family to set
309      */
310     public void setFamily( String theFamily )
311     {
312         this.family = theFamily;
313     }
314 
315     /**
316      * Gets the name.
317      *
318      * @return the name
319      */
320     public String getName()
321     {
322         return this.name;
323     }
324 
325     /**
326      * Sets the name.
327      *
328      * @param theName the name to set
329      */
330     public void setName( String theName )
331     {
332         this.name = theName;
333     }
334 
335     /**
336      * Gets the version.
337      *
338      * @return the version
339      */
340     public String getVersion()
341     {
342         return this.version;
343     }
344 
345     /**
346      * Sets the version.
347      *
348      * @param theVersion the version to set
349      */
350     public void setVersion( String theVersion )
351     {
352         this.version = theVersion;
353     }
354 
355     /**
356      * @param display The value for the display.
357      */
358     public final void setDisplay( boolean display )
359     {
360         this.display = display;
361     }
362 
363     public final boolean isDisplay()
364     {
365         return display;
366     }
367 
368     @Override
369     public String getCacheId()
370     {
371         // return the hashcodes of all the parameters
372         StringBuffer b = new StringBuffer();
373         if ( StringUtils.isNotEmpty( version ) )
374         {
375             b.append( version.hashCode() );
376         }
377         if ( StringUtils.isNotEmpty( name ) )
378         {
379             b.append( name.hashCode() );
380         }
381         if ( StringUtils.isNotEmpty( arch ) )
382         {
383             b.append( arch.hashCode() );
384         }
385         if ( StringUtils.isNotEmpty( family ) )
386         {
387             b.append( family.hashCode() );
388         }
389         return b.toString();
390     }
391 
392     @Override
393     public boolean isCacheable()
394     {
395         // the os is not going to change between projects in the same build.
396         return true;
397     }
398 
399     @Override
400     public boolean isResultValid( EnforcerRule theCachedRule )
401     {
402         // i will always return the hash of the parameters as my id. If my parameters are the same, this
403         // rule must always have the same result.
404         return true;
405     }
406 }