/*******************************************************************************
* Copyright (c) 2017 Synopsys, Inc
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Synopsys, Inc - initial implementation and documentation
*******************************************************************************/
package jenkins.plugins.coverity;
import java.io.Serializable;
import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* An abstract representation of a Coverity version number. Conventional version numbers, as well as current and past
* codenames are all valid and comparable.
*/
public class CoverityVersion implements Comparable<CoverityVersion>, Serializable {
public static final CoverityVersion VERSION_INDIO = new CoverityVersion("indio");
public static final CoverityVersion VERSION_JASPER = new CoverityVersion("jasper");
public static final CoverityVersion MINIMUM_SUPPORTED_VERSION = VERSION_INDIO;
static final Pattern parseRegex = Pattern.compile("(\\d+)\\.(\\d+)\\.(\\d+)(?:\\.(\\d+))?|(\\w+)");
final int major;
final int minor;
final int patch;
final int hotfix;
final String codeName;
final boolean isCodeName;
static final HashMap<String, CoverityVersion> codeNameEquivalents = new HashMap<String, CoverityVersion>();
static {
codeNameEquivalents.put("lodi", new CoverityVersion(8, 6, 0));
codeNameEquivalents.put("kent1", new CoverityVersion(8, 5, 1));
codeNameEquivalents.put("kent", new CoverityVersion(8, 5, 0));
codeNameEquivalents.put("jasper", new CoverityVersion(8, 0, 0));
codeNameEquivalents.put("indio", new CoverityVersion(7, 7, 0));
codeNameEquivalents.put("harmony", new CoverityVersion(7, 6, 0));
codeNameEquivalents.put("gilroy1", new CoverityVersion(7, 5, 1));
codeNameEquivalents.put("gilroy", new CoverityVersion(7, 5, 0));
codeNameEquivalents.put("fresno", new CoverityVersion(7, 0, 0));
codeNameEquivalents.put("eureka", new CoverityVersion(6, 6, 0));
codeNameEquivalents.put("davis", new CoverityVersion(6, 5, 1));
codeNameEquivalents.put("carmel", new CoverityVersion(6, 5, 0));
codeNameEquivalents.put("berkeley", new CoverityVersion(6, 0, 0));
codeNameEquivalents.put("alameda", new CoverityVersion(5, 5, 0));
}
public CoverityVersion(String codeName) {
this.isCodeName = true;
this.codeName = codeName;
this.hotfix = 0;
this.minor = 0;
this.patch = 0;
this.major = 0;
}
public CoverityVersion(int major, int minor, int patch, int hotfix) {
this.isCodeName = false;
this.codeName = null;
this.hotfix = hotfix;
this.minor = minor;
this.patch = patch;
this.major = major;
}
public CoverityVersion(int major, int minor, int patch) {
this.isCodeName = false;
this.codeName = null;
this.hotfix = 0;
this.minor = minor;
this.patch = patch;
this.major = major;
}
public static CoverityVersion parse(String s) {
Matcher m = parseRegex.matcher(s);
if(!m.find()) {
return null;
}
if(m.group(5) != null) {
//codename
return new CoverityVersion(m.group(5));
} else {
//number
return new CoverityVersion(gi(m, 1), gi(m, 2), gi(m, 3), gi(m, 4));
}
}
/**
* Shorthand method. Return an integer from the given group of the given {@link Matcher}
*/
private static int gi(Matcher m, int group) {
if(m.group(group) == null) {
return 0;
}
return Integer.parseInt(m.group(group));
}
/**
* Converts from a codename version to an equivalent numbered version if necessary.
*/
public CoverityVersion getEffectiveVersion() {
if(isCodeName) {
if(codeNameEquivalents.containsKey(codeName)) {
return codeNameEquivalents.get(codeName);
} else {
return new CoverityVersion(0, 0, 0);
}
} else {
return this;
}
}
@Override
public String toString() {
if(isCodeName) {
return codeName;
} else {
return major + "." + minor + "." + patch + (hotfix > 0 ? ("." + hotfix) : "");
}
}
public int compareTo(CoverityVersion o) {
if(isCodeName || o.isCodeName) {
return getEffectiveVersion().compareTo(o.getEffectiveVersion());
} else {
if(major == o.major) {
if(minor == o.minor) {
if(patch == o.patch) {
return cmp(hotfix, o.hotfix);
} else {
return cmp(patch, o.patch);
}
} else {
return cmp(minor, o.minor);
}
} else {
return cmp(major, o.major);
}
}
}
/**
* The way that Compare Major Minor works is that the argument passed in is the analysis version.
* Compares the version's major and minor version number. Returns true if the current version is greater than
* or equals to the passed in version. Else, the compare will return false.
* @param version
* @return
*/
public boolean compareToAnalysis(CoverityVersion version){
if(isCodeName || version.isCodeName){
return getEffectiveVersion().compareToAnalysis(version.getEffectiveVersion());
}else{
if(major == version.major){
return minor >= version.minor;
}else{
return major > version.major;
}
}
}
private int cmp(int a, int b) {
return (a < b ? -1 : (a == b ? 0 : 1));
}
@Override
public boolean equals(Object o) {
if(this == o) {
return true;
}
if(o == null || getClass() != o.getClass()) {
return false;
}
CoverityVersion other = (CoverityVersion) o;
if (isCodeName || other.isCodeName) {
return getEffectiveVersion().equals(other.getEffectiveVersion());
}
if (major != other.major) {
return false;
}
if (minor != other.minor) {
return false;
}
if (patch != other.patch) {
return false;
}
if (hotfix != other.hotfix) {
return false;
}
return true;
}
@Override
public int hashCode() {
int result = 31;
result = 31 * result + major;
result = 31 * result + minor;
result = 31 * result + patch;
result = 31 * result + hotfix;
return result;
}
}