All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.maven.shared.release.versions.DefaultVersionInfo Maven / Gradle / Ivy

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.apache.maven.shared.release.versions;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.ArtifactUtils;
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
import org.codehaus.plexus.util.StringUtils;

/**
 * This compares and increments versions for a common java versioning scheme.
 * 

* The supported version scheme has the following parts.
* component-digits-annotation-annotationRevision-buildSpecifier
* Example:
* my-component-1.0.1-alpha-2-SNAPSHOT * Terms: *

    *
  • component - name of the versioned component (log4j, commons-lang, etc) *
  • digits - Numeric digits with at least one "." period. (1.0, 1.1, 1.01, 1.2.3, etc) *
  • annotationRevision - Integer qualifier for the annotation. (4 as in RC-4) *
  • buildSpecifier - Additional specifier for build. (SNAPSHOT, or build number like "20041114.081234-2") *
* Digits is the only required piece of the version string, and must contain at lease one "." period. * Implementation details:
* The separators "_" and "-" between components are also optional (though they are usually recommended).
* Example:
* log4j-1.2.9-beta-9-SNAPSHOT == log4j1.2.9beta9SNAPSHOT == log4j_1.2.9_beta_9_SNAPSHOT * Leading zeros are significant when performing comparisons. * TODO: this parser is better than DefaultArtifactVersion - replace it with this (but align naming) and then remove * this from here. */ public class DefaultVersionInfo implements VersionInfo { private final String strVersion; private final List digits; private String annotation; private String annotationRevision; private final String buildSpecifier; private String annotationSeparator; private String annotationRevSeparator; private final String buildSeparator; private static final int DIGITS_INDEX = 1; private static final int ANNOTATION_SEPARATOR_INDEX = 2; private static final int ANNOTATION_INDEX = 3; private static final int ANNOTATION_REV_SEPARATOR_INDEX = 4; private static final int ANNOTATION_REVISION_INDEX = 5; private static final int BUILD_SEPARATOR_INDEX = 6; private static final int BUILD_SPECIFIER_INDEX = 7; private static final String SNAPSHOT_IDENTIFIER = "SNAPSHOT"; private static final String DIGIT_SEPARATOR_STRING = "."; /** Constant STANDARD_PATTERN */ public static final Pattern STANDARD_PATTERN = Pattern.compile( "^((?:\\d+\\.)*\\d+)" // digit(s) and '.' repeated - followed by digit (version digits 1.22.0, etc) + "([-_])?" // optional - or _ (annotation separator) + "([a-zA-Z]*)" // alpha characters (looking for annotation - alpha, beta, RC, etc.) + "([-_])?" // optional - or _ (annotation revision separator) + "(\\d*)" // digits (any digits after rc or beta is an annotation revision) + "(?:([-_])?(.*?))?$"); // - or _ followed everything else (build specifier) /* * * cmaki 02242009 * FIX for non-digit release numbers, e.g. trunk-SNAPSHOT or just SNAPSHOT * This alternate pattern supports version numbers like: * trunk-SNAPSHOT * branchName-SNAPSHOT * SNAPSHOT */ // for SNAPSHOT releases only (possible versions include: trunk-SNAPSHOT or SNAPSHOT) /** Constant ALTERNATE_PATTERN */ public static final Pattern ALTERNATE_PATTERN = Pattern.compile("^(SNAPSHOT|[a-zA-Z]+[_-]SNAPSHOT)"); /** * Constructs this object and parses the supplied version string. * * @param version the version string * @throws org.apache.maven.shared.release.versions.VersionParseException if an exception during parsing the input */ public DefaultVersionInfo(String version) throws VersionParseException { strVersion = version; // FIX for non-digit release numbers, e.g. trunk-SNAPSHOT or just SNAPSHOT Matcher matcher = ALTERNATE_PATTERN.matcher(strVersion); // TODO: hack because it didn't support "SNAPSHOT" if (matcher.matches()) { annotation = null; digits = null; buildSpecifier = version; buildSeparator = null; return; } Matcher m = STANDARD_PATTERN.matcher(strVersion); if (m.matches()) { digits = parseDigits(m.group(DIGITS_INDEX)); if (!SNAPSHOT_IDENTIFIER.equals(m.group(ANNOTATION_INDEX))) { annotationSeparator = m.group(ANNOTATION_SEPARATOR_INDEX); annotation = nullIfEmpty(m.group(ANNOTATION_INDEX)); if (StringUtils.isNotEmpty(m.group(ANNOTATION_REV_SEPARATOR_INDEX)) && StringUtils.isEmpty(m.group(ANNOTATION_REVISION_INDEX))) { // The build separator was picked up as the annotation revision separator buildSeparator = m.group(ANNOTATION_REV_SEPARATOR_INDEX); buildSpecifier = nullIfEmpty(m.group(BUILD_SPECIFIER_INDEX)); } else { annotationRevSeparator = m.group(ANNOTATION_REV_SEPARATOR_INDEX); annotationRevision = nullIfEmpty(m.group(ANNOTATION_REVISION_INDEX)); buildSeparator = m.group(BUILD_SEPARATOR_INDEX); buildSpecifier = nullIfEmpty(m.group(BUILD_SPECIFIER_INDEX)); } } else { // Annotation was "SNAPSHOT" so populate the build specifier with that data buildSeparator = m.group(ANNOTATION_SEPARATOR_INDEX); buildSpecifier = nullIfEmpty(m.group(ANNOTATION_INDEX)); } } else { throw new VersionParseException("Unable to parse the version string: \"" + version + "\""); } } /** *

Constructor for DefaultVersionInfo.

* * @param digits a {@link java.util.List} object * @param annotation a {@link java.lang.String} object * @param annotationRevision a {@link java.lang.String} object * @param buildSpecifier a {@link java.lang.String} object * @param annotationSeparator a {@link java.lang.String} object * @param annotationRevSeparator a {@link java.lang.String} object * @param buildSeparator a {@link java.lang.String} object */ public DefaultVersionInfo( List digits, String annotation, String annotationRevision, String buildSpecifier, String annotationSeparator, String annotationRevSeparator, String buildSeparator) { this.digits = digits; this.annotation = annotation; this.annotationRevision = annotationRevision; this.buildSpecifier = buildSpecifier; this.annotationSeparator = annotationSeparator; this.annotationRevSeparator = annotationRevSeparator; this.buildSeparator = buildSeparator; this.strVersion = getVersionString(this, buildSpecifier, buildSeparator); } @Override public boolean isSnapshot() { return ArtifactUtils.isSnapshot(strVersion); } @Override public VersionInfo getNextVersion() { DefaultVersionInfo version = null; if (digits != null) { List digits = new ArrayList<>(this.digits); String annotationRevision = this.annotationRevision; if (StringUtils.isNumeric(annotationRevision)) { annotationRevision = incrementVersionString(annotationRevision); } else { digits.set(digits.size() - 1, incrementVersionString(digits.get(digits.size() - 1))); } version = new DefaultVersionInfo( digits, annotation, annotationRevision, buildSpecifier, annotationSeparator, annotationRevSeparator, buildSeparator); } return version; } /** * {@inheritDoc} * * Compares this {@link DefaultVersionInfo} to the supplied {@link DefaultVersionInfo} to determine which version is * greater. */ @Override public int compareTo(VersionInfo obj) { DefaultVersionInfo that = (DefaultVersionInfo) obj; int result; // TODO: this is a workaround for a bug in DefaultArtifactVersion - fix there - 1.01 < 1.01.01 if (strVersion.startsWith(that.strVersion) && !strVersion.equals(that.strVersion) && strVersion.charAt(that.strVersion.length()) != '-') { result = 1; } else if (that.strVersion.startsWith(strVersion) && !strVersion.equals(that.strVersion) && that.strVersion.charAt(strVersion.length()) != '-') { result = -1; } else { // TODO: this is a workaround for a bug in DefaultArtifactVersion - fix there - it should not consider case // in comparing the qualifier // NOTE: The combination of upper-casing and lower-casing is an approximation of String.equalsIgnoreCase() String thisVersion = strVersion.toUpperCase(Locale.ENGLISH).toLowerCase(Locale.ENGLISH); String thatVersion = that.strVersion.toUpperCase(Locale.ENGLISH).toLowerCase(Locale.ENGLISH); result = new DefaultArtifactVersion(thisVersion).compareTo(new DefaultArtifactVersion(thatVersion)); } return result; } @Override public boolean equals(Object obj) { if (!(obj instanceof DefaultVersionInfo)) { return false; } return compareTo((VersionInfo) obj) == 0; } @Override public int hashCode() { return strVersion.toLowerCase(Locale.ENGLISH).hashCode(); } /** * Takes a string and increments it as an integer. * Preserves any lpad of "0" zeros. * * @param s the version number * @return {@code String} increments the input {@code String} as an integer * and Preserves any lpad of "0" zeros. */ protected String incrementVersionString(String s) { int n = Integer.valueOf(s).intValue() + 1; String value = String.valueOf(n); if (value.length() < s.length()) { // String was left-padded with zeros value = StringUtils.leftPad(value, s.length(), "0"); } return value; } @Override public String getSnapshotVersionString() { if (strVersion.equals(Artifact.SNAPSHOT_VERSION)) { return strVersion; } String baseVersion = getReleaseVersionString(); if (baseVersion.length() > 0) { baseVersion += "-"; } return baseVersion + Artifact.SNAPSHOT_VERSION; } @Override public String getReleaseVersionString() { String baseVersion = strVersion; Matcher m = Artifact.VERSION_FILE_PATTERN.matcher(baseVersion); if (m.matches()) { baseVersion = m.group(1); } // MRELEASE-623 SNAPSHOT is case-insensitive else if (StringUtils.right(baseVersion, 9).equalsIgnoreCase("-" + Artifact.SNAPSHOT_VERSION)) { baseVersion = baseVersion.substring(0, baseVersion.length() - Artifact.SNAPSHOT_VERSION.length() - 1); } else if (baseVersion.equals(Artifact.SNAPSHOT_VERSION)) { baseVersion = "1.0"; } return baseVersion; } @Override public String toString() { return strVersion; } /** *

getVersionString.

* * @param info a {@link org.apache.maven.shared.release.versions.DefaultVersionInfo} object * @param buildSpecifier a {@link java.lang.String} object * @param buildSeparator a {@link java.lang.String} object * @return a {@link java.lang.String} object */ protected static String getVersionString(DefaultVersionInfo info, String buildSpecifier, String buildSeparator) { StringBuilder sb = new StringBuilder(); if (info.digits != null) { sb.append(joinDigitString(info.digits)); } if (info.annotation != null && !info.annotation.isEmpty()) { sb.append(StringUtils.defaultString(info.annotationSeparator)); sb.append(info.annotation); } if (info.annotationRevision != null && !info.annotationRevision.isEmpty()) { if (info.annotation == null || info.annotation.isEmpty()) { sb.append(StringUtils.defaultString(info.annotationSeparator)); } else { sb.append(StringUtils.defaultString(info.annotationRevSeparator)); } sb.append(info.annotationRevision); } if (buildSpecifier != null && !buildSpecifier.isEmpty()) { sb.append(StringUtils.defaultString(buildSeparator)); sb.append(buildSpecifier); } return sb.toString(); } /** * Simply joins the items in the list with "." period * * @return a single {@code String} of the items in the passed list, joined with a "." * @param digits {@code List} of digits */ protected static String joinDigitString(List digits) { return digits != null ? StringUtils.join(digits.iterator(), DIGIT_SEPARATOR_STRING) : null; } /** * Splits the string on "." and returns a list * containing each digit. * * @param strDigits */ private List parseDigits(String strDigits) { return Arrays.asList(StringUtils.split(strDigits, DIGIT_SEPARATOR_STRING)); } // -------------------------------------------------- // Getters & Setters // -------------------------------------------------- private static String nullIfEmpty(String s) { return (s == null || s.isEmpty()) ? null : s; } /** *

Getter for the field digits.

* * @return a {@link java.util.List} object */ public List getDigits() { return digits; } /** *

Getter for the field annotation.

* * @return a {@link java.lang.String} object */ public String getAnnotation() { return annotation; } /** *

Getter for the field annotationRevision.

* * @return a {@link java.lang.String} object */ public String getAnnotationRevision() { return annotationRevision; } /** *

Getter for the field buildSpecifier.

* * @return a {@link java.lang.String} object */ public String getBuildSpecifier() { return buildSpecifier; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy