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

org.apache.maven.shared.release.version.HotfixVersionInfo Maven / Gradle / Ivy

There is a newer version: 1.0-alpha27
Show newest version
package org.apache.maven.shared.release.version;

/*
 * This is a modified version of DefaultVersionInfo from the maven-release-manager
 * project that adds support for creating hotfix versions
 * The original license is as follows:
 */

/*
 * 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.
 */

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.apache.maven.shared.release.versions.VersionInfo;
import org.apache.maven.shared.release.versions.VersionParseException;
import org.codehaus.plexus.util.StringUtils;

public class HotfixVersionInfo 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 = ".";

    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
     */
    public static final Pattern ALTERNATE_PATTERN = Pattern.compile(
            "^(SNAPSHOT|[a-zA-Z]+[_-]SNAPSHOT)"      // for SNAPSHOT releases only (possible versions include: trunk-SNAPSHOT or SNAPSHOT)
    );

    /**
     * Constructs this object and parses the supplied version string.
     *
     * @param version
     */
    public HotfixVersionInfo( 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 + "\"" );
        }
    }

    public HotfixVersionInfo( 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 );
    }

    public boolean isSnapshot()
    {
        return ArtifactUtils.isSnapshot( strVersion );
    }

    public VersionInfo getNextVersion()
    {
        HotfixVersionInfo 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( (String) digits.get( digits.size() - 1 ) ) );
            }

            version = new HotfixVersionInfo( digits, annotation, annotationRevision, buildSpecifier,
                    annotationSeparator, annotationRevSeparator, buildSeparator );
        }
        return version;
    }

    /**
     * Compares this {@link HotfixVersionInfo} to the supplied {@link HotfixVersionInfo}
     * to determine which version is greater.
     *
     * @param obj the comparison version
     * @return the comparison value
     * @throws IllegalArgumentException if the components differ between the objects or if either of the annotations can not be determined.
     */
    public int compareTo( VersionInfo obj )
    {
        HotfixVersionInfo that = (HotfixVersionInfo) 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;
    }

    public boolean equals( Object obj )
    {
        if ( !( obj instanceof HotfixVersionInfo ) )
        {
            return false;
        }

        return compareTo( (VersionInfo) obj ) == 0;
    }

    /**
     * Takes a string and increments it as an integer.
     * Preserves any lpad of "0" zeros.
     *
     * @param s
     */
    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;
    }
    
    public String getSnapshotVersionString()
    {
        if ( strVersion.equals( Artifact.SNAPSHOT_VERSION ) )
        {
            return strVersion;
        }

        String baseVersion = getReleaseVersionString();

        if ( baseVersion.length() > 0 )
        {
            baseVersion += "-";
        }

        return baseVersion + Artifact.SNAPSHOT_VERSION;
    }

    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;
    }

    //if starting at 1.1, returns 1.1.1
    public String getHotfixVersionString()
    {
        HotfixVersionInfo version = null;
        if ( digits != null )
        {
            List digits = new ArrayList( this.digits );
            digits.add("1");

            version = new HotfixVersionInfo( digits, annotation, annotationRevision, buildSpecifier, annotationSeparator, annotationRevSeparator, buildSeparator );
        }
        
        return version.getReleaseVersionString();
    }

    //if starting at 1.1, returns 1.0.1
    public String getDecrementedHotfixVersionString()
    {
        HotfixVersionInfo version = null;
        if ( digits != null )
        {
            List digits = new ArrayList( this.digits );
            
            String lastDigit = digits.get(digits.size() - 1);
            int n = Integer.valueOf(lastDigit).intValue();

            if(n > 0)
            {
                digits.set(digits.size() - 1, Integer.toString(n - 1));
                digits.add("1");
            }
            else
            {
                digits.set(digits.size() - 1, "1");
            }
            
            version = new HotfixVersionInfo( digits, annotation, annotationRevision, buildSpecifier,annotationSeparator, annotationRevSeparator, buildSeparator );
        }
        return version.getReleaseVersionString();
    }

    public String toString()
    {
        return strVersion;
    }

    protected static String getVersionString( HotfixVersionInfo info, String buildSpecifier, String buildSeparator )
    {
        StringBuilder sb = new StringBuilder();

        if ( info.digits != null )
        {
            sb.append( joinDigitString( info.digits ) );
        }

        if ( StringUtils.isNotEmpty( info.annotation ) )
        {
            sb.append( StringUtils.defaultString( info.annotationSeparator ) );
            sb.append( info.annotation );
        }

        if ( StringUtils.isNotEmpty( info.annotationRevision ) )
        {
            if ( StringUtils.isEmpty( info.annotation ) )
            {
                sb.append( StringUtils.defaultString( info.annotationSeparator ) );
            }
            else
            {
                sb.append( StringUtils.defaultString( info.annotationRevSeparator ) );
            }
            sb.append( info.annotationRevision );
        }

        if ( StringUtils.isNotEmpty( buildSpecifier ) )
        {
            sb.append( StringUtils.defaultString( buildSeparator ) );
            sb.append( buildSpecifier );
        }

        return sb.toString();
    }

    /**
     * Simply joins the items in the list with "." period
     *
     * @param 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 StringUtils.isEmpty( s ) ? null : s;
    }

    public List getDigits()
    {
        return digits;
    }

    public String getAnnotation()
    {
        return annotation;
    }

    public String getAnnotationRevision()
    {
        return annotationRevision;
    }

    public String getBuildSpecifier()
    {
        return buildSpecifier;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy