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