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 (message == null || message.isEmpty()) { 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 (family == null || family.isEmpty()) 156 && (arch == null || arch.isEmpty()) 157 && (name == null || name.isEmpty()) 158 && (version == null || version.isEmpty()); 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 (theFamily == null || theFamily.isEmpty()) 225 || Os.getValidFamilies().contains(theFamily); 226 } 227 228 /** 229 * Sets the arch. 230 * 231 * @param theArch the arch to set 232 */ 233 public void setArch(String theArch) { 234 this.arch = theArch; 235 } 236 237 /** 238 * Sets the family. 239 * 240 * @param theFamily the family to set 241 */ 242 public void setFamily(String theFamily) { 243 this.family = theFamily; 244 } 245 246 /** 247 * Sets the name. 248 * 249 * @param theName the name to set 250 */ 251 public void setName(String theName) { 252 this.name = theName; 253 } 254 255 /** 256 * Sets the version. 257 * 258 * @param theVersion the version to set 259 */ 260 public void setVersion(String theVersion) { 261 this.version = theVersion; 262 } 263 264 /** 265 * @param display The value for the display. 266 */ 267 public void setDisplay(boolean display) { 268 this.display = display; 269 } 270 271 @Override 272 public String getCacheId() { 273 // return the hashcodes of all the parameters 274 StringBuilder b = new StringBuilder(); 275 if (version != null && !version.isEmpty()) { 276 b.append(version.hashCode()); 277 } 278 if (name != null && !name.isEmpty()) { 279 b.append(name.hashCode()); 280 } 281 if (arch != null && !arch.isEmpty()) { 282 b.append(arch.hashCode()); 283 } 284 if (family != null && !family.isEmpty()) { 285 b.append(family.hashCode()); 286 } 287 return b.toString(); 288 } 289 290 @Override 291 public String toString() { 292 return String.format( 293 "RequireOS[message=%s, arch=%s, family=%s, name=%s, version=%s, display=%b]", 294 getMessage(), arch, family, name, version, display); 295 } 296}