package org.ovirt.engine.core.compat; import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Class used to extract and represent a version of RPM. It support several patterns: * <li> {@literal <name>-<version>-<release>.<architecture>.rpm} - version part is not allowed to contain "-". * Supported by {@link RpmVersion#RpmVersion(String)} * <li> {@literal <prefix+name>[ -].*<[0-9].*\\.}{1,3}[0-9] {@literal><any text>} e.g: * <i>rhev-agent-2.3.7-1.el6</i> or <i>RHEV-Agent 2.3.395</i>. Supported by {@link RpmVersion#RpmVersion(String, String, boolean)} */ public class RpmVersion extends Version { private static final long serialVersionUID = 5938069430310131270L; private static final String RPM_REGEX = "([^ ]+)\\-([0-9][^ \\-]*\\-[0-9\\.]+)\\.(.*)"; private static final Pattern rpmCompiled = Pattern.compile(RPM_REGEX); private String rpmName; private String rpmRelease; public RpmVersion() { super(); } /** * {@literal Supports RPM format by spec: <name>-<version>-<release>.<architecture>.rpm} * @param rpmName * the RPM name */ public RpmVersion(String rpmName) { this.rpmName = rpmName; setValue(extractRpmVersion(rpmName)); extractRpmRelease(rpmName); } /** * Support RPM version extraction where a given prefix is omitted from the RPM name. * @param rpmName * the full RPM name * @param namePrefix * a prefix which is part of the RPM name and should ignored (case insensitive) while extracting the * version * @param ignoreCaseSensitive * an indicator whether to ignore the case of the given prefix, if known ahead */ public RpmVersion(String rpmName, String namePrefix, boolean ignoreCaseSensitive) { this.rpmName = rpmName; if (rpmName == null || rpmName.isEmpty()) { setValue(rpmName); } else { if (namePrefix == null) { namePrefix = ""; } int start = -1; if (ignoreCaseSensitive) { start = rpmName.toLowerCase().indexOf(namePrefix.toLowerCase()); } else { start = rpmName.indexOf(namePrefix); } String raw; if (start > -1) { raw = rpmName.substring(start + namePrefix.length()); } else { raw = rpmName; } extractRpmRelease(raw); setValue(extractRpmVersion(raw.toCharArray())); } } private void extractRpmRelease(String rpmName) { if (rpmName == null || rpmName.isEmpty()) { return; } int lastDashIndex = rpmName.lastIndexOf('-'); if (lastDashIndex == -1) { return; } rpmRelease = rpmName.substring(lastDashIndex + 1); } public String getRpmName() { return this.rpmName; } public void setRpmName(String rpmName) { this.rpmName = rpmName; } /** * Extracts the version out of a given array of characters by the following algorithm: * <li>Find first digit location after tool name (case ignored). * <li>Parse as many version parts elements as provided, up to 4. * <li>Set default value "0" for the missing parts. * @param version * the char material which contains the version * @return a string contains a version in format of w.x.y.z where w,x,y and z are int. */ private String extractRpmVersion(char[] version) { int start = indexOfFirstDigit(version); int end = version.length; int dots = 3; for (int i = start; i < end; i++) { if (!Character.isDigit(version[i]) && version[i] != '.') { end = i; break; } else if (version[i] == '.') { if (dots == 0) { end = i; break; } dots--; } } StringBuilder sb = new StringBuilder(new String(version, start, end - start)); for (int i = 0; i < dots; i++) { sb.append(".0"); } return sb.toString(); } private String extractRpmVersion(String rpmName) { if (rpmName == null || rpmName.isEmpty()) { return rpmName; } Matcher matchToolPattern = rpmCompiled.matcher(rpmName); String rawString = null; if (matchToolPattern.find() && matchToolPattern.groupCount() > 1) { rawString = matchToolPattern.group(2); return extractRpmVersion(rawString.toCharArray()); } return null; } private static int indexOfFirstDigit(char[] version) { int i = 0; for (; i < version.length; i++) { if (Character.isDigit(version[i])) { break; } } return i; } @Override public int hashCode() { return Objects.hash( super.hashCode(), rpmName ); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof RpmVersion)) { return false; } RpmVersion other = (RpmVersion) obj; return super.equals(obj) && Objects.equals(rpmName, other.rpmName); } public String getRpmRelease() { return rpmRelease; } public void setRpmRelease(String rpmRelease) { this.rpmRelease = rpmRelease; } }