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

com.android.sdklib.repository.FullRevision Maven / Gradle / Ivy

/*
 * Copyright (C) 2012 The Android Open Source Project
 *
 * Licensed 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 com.android.sdklib.repository;

import com.android.annotations.NonNull;

import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 * Package multi-part revision number composed of a tuple
 * (major.minor.micro) and an optional preview revision
 * (the lack of a preview number indicates it's not a preview
 *  but a final package.)
 *
 *  @see MajorRevision
 */
public class FullRevision implements Comparable {

    public static final int MISSING_MAJOR_REV  = 0;
    public static final int IMPLICIT_MINOR_REV = 0;
    public static final int IMPLICIT_MICRO_REV = 0;
    public static final int NOT_A_PREVIEW      = 0;

    /** Only major revision specified: 1 term */
    protected static final int PRECISION_MAJOR = 1;
    /** Only major and minor revisions specified: 2 terms (x.y) */
    protected static final int PRECISION_MINOR = 2;
    /** Major, minor and micro revisions specified: 3 terms (x.y.z) */
    protected static final int PRECISION_MICRO = 3;
    /** Major, minor, micro and preview revisions specified: 4 terms (x.y.z-rcN) */
    protected static final int PRECISION_PREVIEW = 4;

    public static final FullRevision NOT_SPECIFIED = new FullRevision(MISSING_MAJOR_REV);

    private static final Pattern FULL_REVISION_PATTERN =
        //                   1=major       2=minor       3=micro     4=separator  5=previewType  6=preview
        Pattern.compile("\\s*([0-9]+)(?:\\.([0-9]+)(?:\\.([0-9]+))?)?([\\s-]*)?(?:(rc|alpha|beta)([0-9]+))?\\s*");

    protected static final String DEFAULT_SEPARATOR = " ";

    private final int mMajor;
    private final int mMinor;
    private final int mMicro;
    private final int mPreview;
    private final String mPreviewSeparator;
    private final PreviewType mPreviewType;

    public enum PreviewType {
        ALPHA("alpha"),
        BETA("beta"),
        RC("rc")
        ;

        final String name;

        PreviewType(String name) {
            this.name = name;
        }
    }

    public FullRevision(int major) {
        this(major, IMPLICIT_MINOR_REV, IMPLICIT_MICRO_REV);
    }

    public FullRevision(int major, int minor, int micro) {
        this(major, minor, micro, NOT_A_PREVIEW);
    }

    public FullRevision(int major, int minor, int micro, int preview) {
      this(major, minor, micro, PreviewType.RC, preview, DEFAULT_SEPARATOR);
    }

    public FullRevision(int major, int minor, int micro, @NonNull PreviewType previewType,
            int preview, @NonNull String previewSeparator) {
        mMajor = major;
        mMinor = minor;
        mMicro = micro;
        mPreview = preview;
        mPreviewSeparator = previewSeparator;
        mPreviewType = previewType;
    }

    public int getMajor() {
        return mMajor;
    }

    public int getMinor() {
        return mMinor;
    }

    public int getMicro() {
        return mMicro;
    }

    @NonNull
    protected String getSeparator() {
        return mPreviewSeparator;
    }

    public boolean isPreview() {
        return mPreview > NOT_A_PREVIEW;
    }

    public int getPreview() {
        return mPreview;
    }

    /**
     * Parses a string of format "major.minor.micro rcPreview" and returns
     * a new {@link FullRevision} for it. All the fields except major are
     * optional.
     * 

* The parsing is equivalent to the pseudo-BNF/regexp: *

     *   Major/Minor/Micro/Preview := [0-9]+
     *   Revision := Major ('.' Minor ('.' Micro)? )? \s* ('rc'Preview)?
     * 
* * @param revision A non-null revision to parse. * @return A new non-null {@link FullRevision}. * @throws NumberFormatException if the parsing failed. */ @NonNull public static FullRevision parseRevision(@NonNull String revision) throws NumberFormatException { return parseRevisionImpl(revision, true /*supportMinorMicro*/, true /*supportPreview*/, false /*keepPrevision*/); } @NonNull protected static FullRevision parseRevisionImpl(@NonNull String revision, boolean supportMinorMicro, boolean supportPreview, boolean keepPrecision) throws NumberFormatException { if (revision == null) { throw new NumberFormatException("revision is "); //$NON-NLS-1$ } Throwable cause = null; String error = null; try { Matcher m = FULL_REVISION_PATTERN.matcher(revision); if (m != null && m.matches()) { int major = Integer.parseInt(m.group(1)); int minor = IMPLICIT_MINOR_REV; int micro = IMPLICIT_MICRO_REV; int preview = NOT_A_PREVIEW; int precision = PRECISION_MAJOR; String previewSeparator = " "; PreviewType previewType = PreviewType.RC; String s = m.group(2); if (s != null) { if (!supportMinorMicro) { error = " -- Minor number not supported"; //$NON-NLS-1$ } else { minor = Integer.parseInt(s); precision = PRECISION_MINOR; } } s = m.group(3); if (s != null) { if (!supportMinorMicro) { error = " -- Micro number not supported"; //$NON-NLS-1$ } else { micro = Integer.parseInt(s); precision = PRECISION_MICRO; } } s = m.group(6); if (s != null) { if (!supportPreview) { error = " -- Preview number not supported"; //$NON-NLS-1$ } else { preview = Integer.parseInt(s); previewSeparator = m.group(4); precision = PRECISION_PREVIEW; String previewTypeName = m.group(5); for (PreviewType pt : PreviewType.values()) { if (pt.name.equals(previewTypeName)) { previewType = pt; break; } } } } if (error == null) { if (keepPrecision) { return new PreciseRevision(major, minor, micro, preview, precision, previewSeparator); } else { return new FullRevision(major, minor, micro, previewType, preview, previewSeparator); } } } } catch (Throwable t) { cause = t; } NumberFormatException n = new NumberFormatException( "Invalid revision: " //$NON-NLS-1$ + revision + (error == null ? "" : error)); if (cause != null) { n.initCause(cause); } throw n; } /** * Returns the version in a fixed format major.minor.micro * with an optional "rc preview#". For example it would * return "18.0.0", "18.1.0" or "18.1.2 rc5". */ @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append(mMajor) .append('.').append(mMinor) .append('.').append(mMicro); if (mPreview != NOT_A_PREVIEW) { sb.append(mPreviewSeparator).append(mPreviewType.name).append(mPreview); } return sb.toString(); } /** * Returns the version in a dynamic format "major.minor.micro rc#". * This is similar to {@link #toString()} except it omits minor, micro * or preview versions when they are zero. * For example it would return "18 rc1" instead of "18.0.0 rc1", * or "18.1 rc2" instead of "18.1.0 rc2". */ public String toShortString() { StringBuilder sb = new StringBuilder(); sb.append(mMajor); if (mMinor > 0 || mMicro > 0) { sb.append('.').append(mMinor); } if (mMicro > 0) { sb.append('.').append(mMicro); } if (mPreview != NOT_A_PREVIEW) { sb.append(mPreviewSeparator).append(mPreviewType.name).append(mPreview); } return sb.toString(); } /** * Returns the version number as an integer array, in the form * [major, minor, micro] or [major, minor, micro, preview]. * * This is useful to initialize an instance of * {@code org.apache.tools.ant.util.DeweyDecimal} using a * {@link FullRevision}. * * @param includePreview If true the output will contain 4 fields * to include the preview number (even if 0.) If false the output * will contain only 3 fields (major, minor and micro.) * @return A new int array, never null, with either 3 or 4 fields. */ public int[] toIntArray(boolean includePreview) { int size = includePreview ? 4 : 3; int[] result = new int[size]; result[0] = mMajor; result[1] = mMinor; result[2] = mMicro; if (result.length > 3) { result[3] = mPreview; } return result; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + mMajor; result = prime * result + mMinor; result = prime * result + mMicro; result = prime * result + mPreview; result = prime * result + mPreviewType.hashCode(); return result; } @Override public boolean equals(Object rhs) { if (this == rhs) { return true; } if (rhs == null) { return false; } if (!(rhs instanceof FullRevision)) { return false; } FullRevision other = (FullRevision) rhs; if (mMajor != other.mMajor) { return false; } if (mMinor != other.mMinor) { return false; } if (mMicro != other.mMicro) { return false; } if (mPreview != other.mPreview) { return false; } if (mPreviewType != other.mPreviewType) { return false; } return true; } /** * Trivial comparison of a version, e.g 17.1.2 < 18.0.0. * * Note that preview/release candidate are released before their final version, * so "18.0.0 rc1" comes below "18.0.0". The best way to think of it as if the * lack of preview number was "+inf": * "18.1.2 rc5" => "18.1.2.5" so its less than "18.1.2.+INF" but more than "18.1.1.0" * and more than "18.1.2.4" * * @param rhs The right-hand side {@link FullRevision} to compare with. * @return <0 if lhs < rhs; 0 if lhs==rhs; >0 if lhs > rhs. */ @Override public int compareTo(FullRevision rhs) { return compareTo(rhs, PreviewComparison.COMPARE_NUMBER); } /** * Trivial comparison of a version, e.g 17.1.2 < 18.0.0. * * Note that preview/release candidate are released before their final version, * so "18.0.0 rc1" comes below "18.0.0". The best way to think of it as if the * lack of preview number was "+inf": * "18.1.2 rc5" => "18.1.2.5" so its less than "18.1.2.+INF" but more than "18.1.1.0" * and more than "18.1.2.4" * * @param rhs The right-hand side {@link FullRevision} to compare with. * @param comparePreview How to compare the preview value. * @return <0 if lhs < rhs; 0 if lhs==rhs; >0 if lhs > rhs. */ public int compareTo(FullRevision rhs, PreviewComparison comparePreview) { int delta = mMajor - rhs.mMajor; if (delta != 0) { return delta; } delta = mMinor - rhs.mMinor; if (delta != 0) { return delta; } delta = mMicro - rhs.mMicro; if (delta != 0) { return delta; } int p1, p2; switch (comparePreview) { case IGNORE: // Nothing to compare. break; case COMPARE_NUMBER: if (!mPreviewType.equals(rhs.mPreviewType)) { return mPreviewType.compareTo(rhs.mPreviewType); } p1 = mPreview == NOT_A_PREVIEW ? Integer.MAX_VALUE : mPreview; p2 = rhs.mPreview == NOT_A_PREVIEW ? Integer.MAX_VALUE : rhs.mPreview; delta = p1 - p2; break; case COMPARE_TYPE: p1 = mPreview == NOT_A_PREVIEW ? 1 : 0; p2 = rhs.mPreview == NOT_A_PREVIEW ? 1 : 0; delta = p1 - p2; break; } return delta; } /** Indicates how to compare the preview field in * {@link FullRevision#compareTo(FullRevision, PreviewComparison)} */ public enum PreviewComparison { /** Both revisions must have exactly the same preview number. */ COMPARE_NUMBER, /** Both revisions must have the same preview type (both must be previews * or both must not be previews, but the actual number is irrelevant.) * This is the most typical choice used to find updates of the same type. */ COMPARE_TYPE, /** The preview field is ignored and not used in the comparison. */ IGNORE } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy