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