001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.maven.enforcer.rules; 020 021import javax.inject.Inject; 022import javax.inject.Named; 023 024import java.util.Objects; 025 026import org.apache.maven.enforcer.rule.api.EnforcerRuleError; 027import org.apache.maven.enforcer.rule.api.EnforcerRuleException; 028import org.apache.maven.enforcer.rules.utils.OSUtil; 029import org.apache.maven.model.Activation; 030import org.apache.maven.model.ActivationOS; 031import org.apache.maven.model.Profile; 032import org.apache.maven.model.profile.activation.ProfileActivator; 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 */ 042@Named("requireOS") 043public final class RequireOS extends AbstractStandardEnforcerRule { 044 private final ProfileActivator activator; 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 private String family = null; 063 064 /** 065 * The OS name desired. 066 */ 067 private String name = null; 068 069 /** 070 * The OS version desired. 071 */ 072 private String version = null; 073 074 /** 075 * The OS architecture desired. 076 */ 077 private String arch = null; 078 079 /** 080 * Display detected OS information. 081 */ 082 private boolean display = false; 083 084 /** 085 * Instantiates a new RequireOS. 086 */ 087 @Inject 088 RequireOS(@Named("os") ProfileActivator activator) { 089 this.activator = Objects.requireNonNull(activator); 090 } 091 092 @Override 093 public void execute() throws EnforcerRuleException { 094 095 displayOSInfo(); 096 097 if (allParamsEmpty()) { 098 throw new EnforcerRuleError("All parameters can not be empty. " 099 + "You must pick at least one of (family, name, version, arch), " 100 + "you can use mvn --version to see the current OS information."); 101 } 102 103 if (isValidFamily(this.family)) { 104 if (!isAllowed()) { 105 String message = getMessage(); 106 if (StringUtils.isEmpty(message)) { 107 // @formatter:off 108 message = ("OS Arch: " 109 + Os.OS_ARCH + " Family: " 110 + Os.OS_FAMILY + " Name: " 111 + Os.OS_NAME + " Version: " 112 + Os.OS_VERSION + " is not allowed by" + (arch != null ? " Arch=" + arch : "") 113 + (family != null ? " Family=" + family : "") 114 + (name != null ? " Name=" + name : "") 115 + (version != null ? " Version=" + version : "")); 116 // @formatter:on 117 } 118 throw new EnforcerRuleException(message); 119 } 120 } else { 121 String validFamilies = String.join(",", Os.getValidFamilies()); 122 throw new EnforcerRuleError("Invalid Family type used. Valid family types are: " + validFamilies); 123 } 124 } 125 126 /** 127 * Log the current OS information. 128 */ 129 private void displayOSInfo() { 130 String string = OSUtil.getOSInfo(); 131 132 if (!display) { 133 getLog().debug(string); 134 } else { 135 getLog().info(string); 136 } 137 } 138 139 /** 140 * Helper method to determine if the current OS is allowed based on the injected values for family, name, version 141 * and arch. 142 * 143 * @return true if the version is allowed. 144 */ 145 public boolean isAllowed() { 146 return activator.isActive(createProfile(), null, null); 147 } 148 149 /** 150 * Helper method to check that at least one of family, name, version or arch is set. 151 * 152 * @return true if all parameters are empty. 153 */ 154 public boolean allParamsEmpty() { 155 return (StringUtils.isEmpty(family) 156 && StringUtils.isEmpty(arch) 157 && StringUtils.isEmpty(name) 158 && StringUtils.isEmpty(version)); 159 } 160 161 /** 162 * Creates a Profile object that contains the activation information. 163 * 164 * @return a properly populated profile to be used for OS validation. 165 */ 166 private Profile createProfile() { 167 Profile profile = new Profile(); 168 profile.setActivation(createActivation()); 169 return profile; 170 } 171 172 /** 173 * Creates an Activation object that contains the ActivationOS information. 174 * 175 * @return a properly populated Activation object. 176 */ 177 private Activation createActivation() { 178 Activation activation = new Activation(); 179 activation.setActiveByDefault(false); 180 activation.setOs(createOsBean()); 181 return activation; 182 } 183 184 /** 185 * Creates an ActivationOS object containing family, name, version and arch. 186 * 187 * @return a properly populated ActivationOS object. 188 */ 189 private ActivationOS createOsBean() { 190 ActivationOS os = new ActivationOS(); 191 192 os.setArch(arch); 193 os.setFamily(family); 194 os.setName(name); 195 os.setVersion(version); 196 197 return os; 198 } 199 200 /** 201 * Helper method to check if the given family is in the following list: 202 * <ul> 203 * <li>dos</li> 204 * <li>mac</li> 205 * <li>netware</li> 206 * <li>os/2</li> 207 * <li>tandem</li> 208 * <li>unix</li> 209 * <li>windows</li> 210 * <li>win9x</li> 211 * <li>z/os</li> 212 * <li>os/400</li> 213 * </ul> 214 * Note: '!' is allowed at the beginning of the string and still considered valid. 215 * 216 * @param theFamily the family to check. 217 * @return true if one of the valid families. 218 */ 219 public boolean isValidFamily(String theFamily) { 220 221 // in case they are checking !family 222 theFamily = StringUtils.stripStart(theFamily, "!"); 223 224 return (StringUtils.isEmpty(theFamily) || Os.getValidFamilies().contains(theFamily)); 225 } 226 227 /** 228 * Sets the arch. 229 * 230 * @param theArch the arch to set 231 */ 232 public void setArch(String theArch) { 233 this.arch = theArch; 234 } 235 236 /** 237 * Sets the family. 238 * 239 * @param theFamily the family to set 240 */ 241 public void setFamily(String theFamily) { 242 this.family = theFamily; 243 } 244 245 /** 246 * Sets the name. 247 * 248 * @param theName the name to set 249 */ 250 public void setName(String theName) { 251 this.name = theName; 252 } 253 254 /** 255 * Sets the version. 256 * 257 * @param theVersion the version to set 258 */ 259 public void setVersion(String theVersion) { 260 this.version = theVersion; 261 } 262 263 /** 264 * @param display The value for the display. 265 */ 266 public void setDisplay(boolean display) { 267 this.display = display; 268 } 269 270 @Override 271 public String getCacheId() { 272 // return the hashcodes of all the parameters 273 StringBuilder b = new StringBuilder(); 274 if (StringUtils.isNotEmpty(version)) { 275 b.append(version.hashCode()); 276 } 277 if (StringUtils.isNotEmpty(name)) { 278 b.append(name.hashCode()); 279 } 280 if (StringUtils.isNotEmpty(arch)) { 281 b.append(arch.hashCode()); 282 } 283 if (StringUtils.isNotEmpty(family)) { 284 b.append(family.hashCode()); 285 } 286 return b.toString(); 287 } 288 289 @Override 290 public String toString() { 291 return String.format( 292 "RequireOS[message=%s, arch=%s, family=%s, name=%s, version=%s, display=%b]", 293 getMessage(), arch, family, name, version, display); 294 } 295}