001package org.apache.maven.plugins.enforcer; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import java.util.Iterator; 023 024import org.apache.maven.enforcer.rule.api.EnforcerRule; 025import org.apache.maven.enforcer.rule.api.EnforcerRuleException; 026import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper; 027import org.apache.maven.model.Activation; 028import org.apache.maven.model.ActivationOS; 029import org.apache.maven.model.Profile; 030import org.apache.maven.plugin.logging.Log; 031import org.apache.maven.model.profile.activation.ProfileActivator; 032import org.codehaus.plexus.component.repository.exception.ComponentLookupException; 033import org.codehaus.plexus.util.Os; 034import org.codehaus.plexus.util.StringUtils; 035 036/** 037 * This rule checks that the OS is allowed by combinations of family, name, version and cpu architecture. The behavior 038 * is exactly the same as the Maven Os profile activation so the same values are allowed here. 039 * 040 * @author <a href="mailto:brianf@apache.org">Brian Fox</a> 041 */ 042public class RequireOS 043 extends AbstractStandardEnforcerRule 044{ 045 private ProfileActivator activator; 046 047 /** 048 * The OS family type desired<br /> 049 * Possible values: 050 * <ul> 051 * <li>dos</li> 052 * <li>mac</li> 053 * <li>netware</li> 054 * <li>os/2</li> 055 * <li>tandem</li> 056 * <li>unix</li> 057 * <li>windows</li> 058 * <li>win9x</li> 059 * <li>z/os</li> 060 * <li>os/400</li> 061 * </ul> 062 * 063 * @see {@link #setFamily(String)} 064 * @see {@link #getFamily()} 065 */ 066 private String family = null; 067 068 /** 069 * The OS name desired. 070 * 071 * @see {@link #setName(String)} 072 * @see {@link #getName()} 073 */ 074 private String name = null; 075 076 /** 077 * The OS version desired. 078 * 079 * @see {@link #setVersion(String)} 080 * @see {@link #getVersion()} 081 */ 082 private String version = null; 083 084 /** 085 * The OS architecture desired. 086 * 087 * @see {@link #setArch(String)} 088 * @see {@link #getArch()} 089 */ 090 private String arch = null; 091 092 /** 093 * Display detected OS information. 094 * 095 * @see {@link #setDisplay(boolean)} 096 * @see {@link #isDisplay()} 097 */ 098 private boolean display = false; 099 100 /** 101 * Instantiates a new RequireOS. 102 */ 103 public RequireOS() 104 { 105 106 } 107 108 // For testing 109 RequireOS( ProfileActivator activator ) 110 { 111 this.activator = activator; 112 } 113 114 115 @Override 116 public void execute( EnforcerRuleHelper helper ) 117 throws EnforcerRuleException 118 { 119 120 displayOSInfo( helper.getLog(), display ); 121 122 if ( allParamsEmpty() ) 123 { 124 throw new EnforcerRuleException( "All parameters can not be empty. " 125 + "You must pick at least one of (family, name, version, arch) " 126 + "or use -Denforcer.os.display=true to see the current OS information." ); 127 } 128 129 try 130 { 131 activator = helper.getComponent( ProfileActivator.class, "os" ); 132 } 133 catch ( ComponentLookupException e ) 134 { 135 throw new EnforcerRuleException( e.getMessage() ); 136 } 137 138 if ( isValidFamily( this.family ) ) 139 { 140 if ( !isAllowed() ) 141 { 142 String message = getMessage(); 143 if ( StringUtils.isEmpty( message ) ) 144 { 145 //@formatter:off 146 message = 147 ( "OS Arch: " 148 + Os.OS_ARCH + " Family: " 149 + Os.OS_FAMILY + " Name: " 150 + Os.OS_NAME + " Version: " 151 + Os.OS_VERSION + " is not allowed by" + ( arch != null ? " Arch=" + arch : "" ) 152 + ( family != null ? " Family=" + family : "" ) 153 + ( name != null ? " Name=" + name : "" ) 154 + ( version != null ? " Version=" + version : "" ) ); 155 //@formatter:on 156 } 157 throw new EnforcerRuleException( message ); 158 } 159 } 160 else 161 { 162 final int minimumBufferSize = 50; 163 StringBuilder buffer = new StringBuilder( minimumBufferSize ); 164 Iterator<?> iter = Os.getValidFamilies().iterator(); 165 while ( iter.hasNext() ) 166 { 167 buffer.append( iter.next() ); 168 buffer.append( ", " ); 169 } 170 String help = StringUtils.stripEnd( buffer.toString().trim(), "." ); 171 throw new EnforcerRuleException( "Invalid Family type used. Valid family types are: " + help ); 172 } 173 } 174 175 /** 176 * Log the current OS information. 177 * 178 * @param log the log 179 * @param info the info 180 */ 181 public void displayOSInfo( Log log, boolean info ) 182 { 183 String string = 184 "OS Info: Arch: " + Os.OS_ARCH + " Family: " + Os.OS_FAMILY + " Name: " + Os.OS_NAME + " Version: " 185 + Os.OS_VERSION; 186 187 if ( !info ) 188 { 189 log.debug( string ); 190 } 191 else 192 { 193 log.info( string ); 194 } 195 } 196 197 /** 198 * Helper method to determine if the current OS is allowed based on the injected values for family, name, version 199 * and arch. 200 * 201 * @return true if the version is allowed. 202 */ 203 public boolean isAllowed() 204 { 205 return activator.isActive( createProfile(), null, null ); 206 } 207 208 /** 209 * Helper method to check that at least one of family, name, version or arch is set. 210 * 211 * @return true if all parameters are empty. 212 */ 213 public boolean allParamsEmpty() 214 { 215 // CHECKSTYLE_OFF: LineLength 216 return ( StringUtils.isEmpty( family ) && StringUtils.isEmpty( arch ) && StringUtils.isEmpty( name ) && StringUtils.isEmpty( version ) ); 217 // CHECKSTYLE_ON: LineLength 218 } 219 220 /** 221 * Creates a Profile object that contains the activation information. 222 * 223 * @return a properly populated profile to be used for OS validation. 224 */ 225 private Profile createProfile() 226 { 227 Profile profile = new Profile(); 228 profile.setActivation( createActivation() ); 229 return profile; 230 } 231 232 /** 233 * Creates an Activation object that contains the ActivationOS information. 234 * 235 * @return a properly populated Activation object. 236 */ 237 private Activation createActivation() 238 { 239 Activation activation = new Activation(); 240 activation.setActiveByDefault( false ); 241 activation.setOs( createOsBean() ); 242 return activation; 243 } 244 245 /** 246 * Creates an ActivationOS object containing family, name, version and arch. 247 * 248 * @return a properly populated ActivationOS object. 249 */ 250 private ActivationOS createOsBean() 251 { 252 ActivationOS os = new ActivationOS(); 253 254 os.setArch( arch ); 255 os.setFamily( family ); 256 os.setName( name ); 257 os.setVersion( version ); 258 259 return os; 260 } 261 262 /** 263 * Helper method to check if the given family is in the following list: 264 * <ul> 265 * <li>dos</li> 266 * <li>mac</li> 267 * <li>netware</li> 268 * <li>os/2</li> 269 * <li>tandem</li> 270 * <li>unix</li> 271 * <li>windows</li> 272 * <li>win9x</li> 273 * <li>z/os</li> 274 * <li>os/400</li> 275 * </ul> 276 * Note: '!' is allowed at the beginning of the string and still considered valid. 277 * 278 * @param theFamily the family to check. 279 * @return true if one of the valid families. 280 */ 281 public boolean isValidFamily( String theFamily ) 282 { 283 284 // in case they are checking !family 285 theFamily = StringUtils.stripStart( theFamily, "!" ); 286 287 return ( StringUtils.isEmpty( theFamily ) || Os.getValidFamilies().contains( theFamily ) ); 288 } 289 290 /** 291 * Gets the arch. 292 * 293 * @return the arch 294 */ 295 public String getArch() 296 { 297 return this.arch; 298 } 299 300 /** 301 * Sets the arch. 302 * 303 * @param theArch the arch to set 304 */ 305 public void setArch( String theArch ) 306 { 307 this.arch = theArch; 308 } 309 310 /** 311 * Gets the family. 312 * 313 * @return the family 314 */ 315 public String getFamily() 316 { 317 return this.family; 318 } 319 320 /** 321 * Sets the family. 322 * 323 * @param theFamily the family to set 324 */ 325 public void setFamily( String theFamily ) 326 { 327 this.family = theFamily; 328 } 329 330 /** 331 * Gets the name. 332 * 333 * @return the name 334 */ 335 public String getName() 336 { 337 return this.name; 338 } 339 340 /** 341 * Sets the name. 342 * 343 * @param theName the name to set 344 */ 345 public void setName( String theName ) 346 { 347 this.name = theName; 348 } 349 350 /** 351 * Gets the version. 352 * 353 * @return the version 354 */ 355 public String getVersion() 356 { 357 return this.version; 358 } 359 360 /** 361 * Sets the version. 362 * 363 * @param theVersion the version to set 364 */ 365 public void setVersion( String theVersion ) 366 { 367 this.version = theVersion; 368 } 369 370 /** 371 * @param display The value for the display. 372 */ 373 public final void setDisplay( boolean display ) 374 { 375 this.display = display; 376 } 377 378 public final boolean isDisplay() 379 { 380 return display; 381 } 382 383 @Override 384 public String getCacheId() 385 { 386 // return the hashcodes of all the parameters 387 StringBuffer b = new StringBuffer(); 388 if ( StringUtils.isNotEmpty( version ) ) 389 { 390 b.append( version.hashCode() ); 391 } 392 if ( StringUtils.isNotEmpty( name ) ) 393 { 394 b.append( name.hashCode() ); 395 } 396 if ( StringUtils.isNotEmpty( arch ) ) 397 { 398 b.append( arch.hashCode() ); 399 } 400 if ( StringUtils.isNotEmpty( family ) ) 401 { 402 b.append( family.hashCode() ); 403 } 404 return b.toString(); 405 } 406 407 @Override 408 public boolean isCacheable() 409 { 410 // the os is not going to change between projects in the same build. 411 return true; 412 } 413 414 @Override 415 public boolean isResultValid( EnforcerRule theCachedRule ) 416 { 417 // i will always return the hash of the parameters as my id. If my parameters are the same, this 418 // rule must always have the same result. 419 return true; 420 } 421}