/******************************************************************************* * Copyright (c) 2012, 2016, 2017 PDT Extension Group and others. * 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: * PDT Extension Group - initial API and implementation * Kaloyan Raev - [501269] externalize strings *******************************************************************************/ package org.eclipse.php.composer.api.entities; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.eclipse.php.composer.api.ComposerConstants; public class Version extends Entity implements Comparable<Version> { public final static int BEGIN = 0; public final static int END = 1; private List<Version> versions = new ArrayList<Version>(); /** * Passed version string */ private String version; private String constraint = ""; //$NON-NLS-1$ private String stabilityModifier = ""; //$NON-NLS-1$ private String major = ""; //$NON-NLS-1$ private String minor = ""; //$NON-NLS-1$ private String fix = ""; //$NON-NLS-1$ private String build = ""; //$NON-NLS-1$ private String stability = ""; //$NON-NLS-1$ private String suffix = ""; //$NON-NLS-1$ private String prefix = ""; //$NON-NLS-1$ private int devPosition = END; public Version() { } public Version(String version) { parse(version); } private void parse(String version) { // reset clear(); // start parsing if (version.matches(",")) { //$NON-NLS-1$ String parts[] = version.split(","); //$NON-NLS-1$ // lowest = this versions.add(this); parseVersion(parts[0]); // all higher ones for (int i = 1; i < parts.length; i++) { Version v = new Version(parts[i]); v.addPropertyChangeListener(new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent evt) { reset(); } }); versions.add(v); } // reset this.version = null; } else { parseVersion(version); } } private void parseVersion(String version) { this.version = version; String parts[]; // constraint String constraintPattern = "^(<>|!=|>=?|<=?|==?)?(.+)"; //$NON-NLS-1$ if (version.matches(constraintPattern)) { constraint = version.replaceAll(constraintPattern, "$1"); //$NON-NLS-1$ version = version.replaceAll(constraintPattern, "$2"); //$NON-NLS-1$ } // stability modifier if (version.matches(".+@.+")) { //$NON-NLS-1$ parts = version.split("@"); //$NON-NLS-1$ version = parts[0]; stabilityModifier = normalizeStability(parts[1]); } // dev version? if (version.startsWith("dev-")) { //$NON-NLS-1$ stability = ComposerConstants.DEV; version = version.substring(4); devPosition = BEGIN; } parts = version.split("-"); //$NON-NLS-1$ int len = parts.length; if (len > 0) { parseMain(parts[0]); } if (len > 1) { parseTail(parts[1]); } if (stability.isEmpty()) { stability = ComposerConstants.STABLE; } } private void parseMain(String main) { if (main.contains(".")) { //$NON-NLS-1$ String parts[] = main.split("\\."); //$NON-NLS-1$ int len = parts.length; if (len > 0) { Pattern pattern = Pattern.compile("(\\D+)?(\\d+)", Pattern.CASE_INSENSITIVE); //$NON-NLS-1$ Matcher matcher = pattern.matcher(parts[0]); matcher.find(); if (matcher.group(1) != null) { prefix = matcher.group(1); } if (matcher.group(2) != null) { major = matcher.group(2); } } if (len > 1) { minor = parts[1]; } if (len > 2) { fix = parts[2]; } if (len > 3) { build = parts[3]; } } else { major = main; } } private void parseTail(String tail) { Pattern pattern = Pattern.compile("[._-]?(?:(stable|beta|b|RC|alpha|a|patch|pl|p)(?:[.-]?(\\d+))?)?([.-]?dev)?", //$NON-NLS-1$ Pattern.CASE_INSENSITIVE); Matcher matcher = pattern.matcher(tail); matcher.find(); if (matcher.group(2) != null && !matcher.group(2).isEmpty()) { suffix = matcher.group(2); } // stability if (stability.isEmpty()) { // -dev present? if (matcher.group(3) != null && !matcher.group(3).isEmpty()) { stability = ComposerConstants.DEV; } // stability else if (matcher.group(1) != null && !matcher.group(1).isEmpty()) { stability = normalizeStability(matcher.group(1)); } } } private String normalizeStability(String stabi) { if (stabi.equalsIgnoreCase("dev")) { //$NON-NLS-1$ return ComposerConstants.DEV; } if (stabi.equalsIgnoreCase("beta") || stabi.equalsIgnoreCase("b")) { //$NON-NLS-1$ //$NON-NLS-2$ return ComposerConstants.BETA; } if (stabi.equalsIgnoreCase("alpha") || stabi.equalsIgnoreCase("a")) { //$NON-NLS-1$ //$NON-NLS-2$ return ComposerConstants.ALPHA; } if (stabi.equalsIgnoreCase("rc")) { //$NON-NLS-1$ return ComposerConstants.RC; } if (stabi.equalsIgnoreCase("stable")) { //$NON-NLS-1$ return ComposerConstants.STABLE; } return ""; //$NON-NLS-1$ } private String build() { StringBuilder sb = new StringBuilder(); if (!constraint.isEmpty()) { sb.append(constraint); } if (devPosition == BEGIN && stability == ComposerConstants.DEV) { sb.append("dev-"); //$NON-NLS-1$ } if (!prefix.isEmpty()) { sb.append(prefix); } sb.append(major); if (!minor.isEmpty()) { sb.append("."); //$NON-NLS-1$ sb.append(minor); } if (!fix.isEmpty()) { sb.append("."); //$NON-NLS-1$ sb.append(fix); } if (!build.isEmpty()) { sb.append("."); //$NON-NLS-1$ sb.append(build); } StringBuilder sx = new StringBuilder(); if (!stability.isEmpty() && stability != ComposerConstants.STABLE && (stability == ComposerConstants.DEV ? devPosition != BEGIN : true)) { sx.append(stability); } if (!suffix.isEmpty()) { sx.append(suffix); } if (sx.length() > 0) { sb.append("-"); //$NON-NLS-1$ sb.append(sx); } if (!stabilityModifier.isEmpty()) { sb.append("@"); //$NON-NLS-1$ sb.append(stabilityModifier); } if (versions.size() > 0) { int i = 1; for (Version v : versions) { sb.append(v.toString()); if (i < versions.size()) { sb.append(","); //$NON-NLS-1$ } i++; } } return sb.toString(); } public boolean hasRange() { return versions.size() > 0; } public Version getLowest() { return this; } public Version getHighest() { if (versions == null) { return null; } return versions.get(versions.size() - 1); } public void clear() { versions.clear(); constraint = ""; //$NON-NLS-1$ stabilityModifier = ""; //$NON-NLS-1$ major = ""; //$NON-NLS-1$ minor = ""; //$NON-NLS-1$ fix = ""; //$NON-NLS-1$ build = ""; //$NON-NLS-1$ stability = ""; //$NON-NLS-1$ suffix = ""; //$NON-NLS-1$ prefix = ""; //$NON-NLS-1$ devPosition = END; version = null; } public Version getVersion(int index) { if (versions.size() > index) { return versions.get(index); } return null; } public List<Version> getVersions() { return versions; } public void add(Version version) { versions.add(versions.size(), version); } public void add(int index, Version version) { versions.add(index, version); reset(); } private void reset() { version = ""; //$NON-NLS-1$ } /** * @return the version */ public String toString() { if ("".equals(version) || version == null) { //$NON-NLS-1$ version = build(); } return version; } /** * @return the constraint */ public String getConstraint() { return constraint; } /** * @return the stabilityModifier */ public String getStabilityModifier() { return stabilityModifier; } /** * @return the major */ public String getMajor() { return major; } /** * @return the minor */ public String getMinor() { return minor; } /** * @return the fix */ public String getFix() { return fix; } /** * @return the build */ public String getBuild() { return build; } /** * @return the stability */ public String getStability() { return stability; } /** * @return the suffix */ public String getSuffix() { return suffix; } /** * @param version * the version to set */ public void setVersion(String version) { String oldVersion = this.version; versions.clear(); parse(version); firePropertyChange("version", oldVersion, this.version); //$NON-NLS-1$ } public void from(Version version) { String oldVersion = this.version; reset(); versions.clear(); versions.addAll(version.getVersions()); constraint = version.getConstraint(); stabilityModifier = version.getStabilityModifier(); major = version.getMajor(); minor = version.getMinor(); fix = version.getFix(); build = version.getBuild(); stability = version.getStability(); suffix = version.getSuffix(); prefix = version.getPrefix(); devPosition = version.getDevPosition(); firePropertyChange("version", oldVersion, toString()); //$NON-NLS-1$ } /** * @param constraint * the constraint to set */ public void setConstraint(String constraint) { reset(); firePropertyChange("constraint", this.constraint, this.constraint = constraint); //$NON-NLS-1$ } /** * @param stabilityModifier * the stabilityModifier to set */ public void setStabilityModifier(String stabilityModifier) { reset(); firePropertyChange("stabilityModifier", this.stabilityModifier, this.stabilityModifier = stabilityModifier); //$NON-NLS-1$ } /** * @param major * the major to set */ public void setMajor(String major) { reset(); firePropertyChange("major", this.major, this.major = major); //$NON-NLS-1$ } /** * @param minor * the minor to set */ public void setMinor(String minor) { reset(); firePropertyChange("minor", this.minor, this.minor = minor); //$NON-NLS-1$ } /** * @param fix * the fix to set */ public void setFix(String fix) { reset(); firePropertyChange("fix", this.fix, this.fix = fix); //$NON-NLS-1$ } /** * @param build * the build to set */ public void setBuild(String build) { reset(); firePropertyChange("build", this.build, this.build = build); //$NON-NLS-1$ } /** * @param stability * the stability to set */ public void setStability(String stability) { reset(); firePropertyChange("stability", this.stability, this.stability = stability); //$NON-NLS-1$ } /** * @param suffix * the suffix to set */ public void setSuffix(String suffix) { reset(); firePropertyChange("suffix", this.suffix, this.suffix = suffix); //$NON-NLS-1$ } public int getDevPosition() { return devPosition; } public void setDevPosition(int devPosition) { reset(); firePropertyChange("devPosition", this.devPosition, this.devPosition = devPosition); //$NON-NLS-1$ } public String getPrefix() { return prefix; } public void setPrefix(String prefix) { reset(); firePropertyChange("prefix", this.prefix, this.prefix = prefix); //$NON-NLS-1$ } public int compareTo(Version anotherVersion) { if ("dev-master".equals(toString())) { //$NON-NLS-1$ return -1; } if ("dev-master".equals(anotherVersion.toString())) { //$NON-NLS-1$ return 1; } // major int major = cmp(getMajor(), anotherVersion.getMajor()); if (major == 0) { int minor = cmp(getMinor(), anotherVersion.getMinor()); if (minor == 0) { int fix = cmp(getFix(), anotherVersion.getFix()); if (fix == 0) { int build = cmp(getBuild(), anotherVersion.getBuild()); if (build == 0) { int s1 = Arrays.binarySearch(ComposerConstants.STABILITIES, getStability()); int s2 = Arrays.binarySearch(ComposerConstants.STABILITIES, anotherVersion.getStability()); if (s1 == s2) { return cmp(getSuffix(), anotherVersion.getSuffix()); } else { return s1 > s2 ? -1 : 1; } } else { return build; } } else { return fix; } } else { return minor; } } else { return major; } } private int cmp(String s1, String s2) { // ints int i1 = 0, i2 = 0; // true = string contains chars, false = integer boolean l1 = true, l2 = true; // convert try { i1 = Integer.parseInt(s1, 10); l1 = false; } catch (Exception e) { } try { i2 = Integer.parseInt(s2, 10); l2 = false; } catch (Exception e) { } // both string if (l1 && l2) { return s1.compareTo(s2); } // l1 string, l2 integer if (l1 && !l2) { return 1; } // l1 integer, l2 string if (!l1 && l2) { return -1; } // both integer if (i1 == i2) { return 0; } return i1 > i2 ? 1 : -1; } }