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

org.graalvm.home.Version Maven / Gradle / Ivy

/*
 * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * The Universal Permissive License (UPL), Version 1.0
 *
 * Subject to the condition set forth below, permission is hereby granted to any
 * person obtaining a copy of this software, associated documentation and/or
 * data (collectively the "Software"), free of charge and under any and all
 * copyright rights in the Software, and any and all patent rights owned or
 * freely licensable by each licensor hereunder covering either (i) the
 * unmodified Software as contributed to or provided by such licensor, or (ii)
 * the Larger Works (as defined below), to deal in both
 *
 * (a) the Software, and
 *
 * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
 * one is included with the Software each a "Larger Work" to which the Software
 * is contributed by such licensors),
 *
 * without restriction, including without limitation the rights to copy, create
 * derivative works of, display, perform, and distribute the Software and make,
 * use, sell, offer for sale, import, export, have made, and have sold the
 * Software and the Larger Work(s), and to sublicense the foregoing rights on
 * either these or other terms.
 *
 * This license is subject to the following condition:
 *
 * The above copyright notice and either this complete permission notice or at a
 * minimum a reference to the UPL must be included in all copies or substantial
 * portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package org.graalvm.home;

import java.util.Arrays;
import java.util.Objects;

/**
 * A version utility to canonicalize and compare GraalVM versions. The GraalVM version string is not
 * standardized and may change without notice. This class is designed to evolve with GraalVM to
 * cover all used version formats in use. It allows to create, validate and compare GraalVM
 * versions. Do not rely on the format of the raw version string or the result of
 * {@link #toString()}, only use it to produce output for humans.
 * 

* To create version instances of a particular version use the {@link #create(int...)} factory * method. Use {@link #getCurrent()} to lookup the current GraalVM version or {@link #parse(String)} * to parse it from a raw string. *

* *

Usage example:

This code example compares the current GraalVM version to be at least * 19.3 and fails if it is not. * *
 * if (Version.getCurrent().compareTo(19, 3) < 0) {
 *     throw new IllegalStateException("Invalid GraalVM version. Must be at least 19.3.");
 * }
 * 
*

* Note: this class has a natural ordering that is inconsistent with equals. * * @see HomeFinder#getVersion() * @since 19.3 */ public final class Version implements Comparable { private static final String SNAPSHOT_STRING = "snapshot"; private static final String SNAPSHOT_SUFFIX = "dev"; private static final int MIN_VERSION_DIGITS = 3; private final int[] versions; private final String suffix; private final boolean snapshot; Version(int... versions) { this.versions = versions; this.suffix = null; this.snapshot = false; } Version(String v) { if (v.equals(SNAPSHOT_STRING) || v.equals("dev")) { snapshot = true; versions = new int[0]; suffix = SNAPSHOT_STRING; } else { int dash = v.indexOf('-'); int end; if (dash != -1) { suffix = v.substring(dash + 1, v.length()); snapshot = suffix.equals(SNAPSHOT_SUFFIX); end = dash; } else { suffix = null; snapshot = false; end = v.length(); } String versionsString = v.substring(0, end); // -1 to also include trailing empty strings. String[] versionChunks = versionsString.split("\\.", -1); int[] intVersions = new int[versionChunks.length]; for (int i = 0; i < versionChunks.length; i++) { try { intVersions[i] = Integer.parseInt(versionChunks[i]); } catch (NumberFormatException f) { throw invalid(v); } // versions cannot be negative as we would already // cut at the first occurrence of '-' assert intVersions[i] >= 0; } // trim trailing zeros intVersions = trimTrailingZeros(intVersions); if (intVersions.length == 0) { throw invalid(v); } this.versions = intVersions; } } private static int[] trimTrailingZeros(int[] intVersions) { int trimVersions = intVersions.length - 1; for (; trimVersions >= 0; trimVersions--) { if (intVersions[trimVersions] != 0) { break; } } if (trimVersions != intVersions.length - 1) { return Arrays.copyOf(intVersions, trimVersions + 1); } else { return intVersions; } } private static IllegalArgumentException invalid(String v) { return new IllegalArgumentException("Invalid version string '" + v + "'."); } /** * Returns true if this is a supported release build of GraalVM else * false. Use this for implementation assertions that verify that only releases are * deployed to production. * * @see #isSnapshot() * @since 19.3 */ public boolean isRelease() { return !snapshot; } /** * Returns true if this is an unsupported snapshot build of GraalVM else * false. Use this for implementation assertions that verify that only releases are * deployed to production. * * @see #isSnapshot() * @since 19.3 */ public boolean isSnapshot() { return snapshot; } /** * {@inheritDoc} * * @since 19.3 */ @Override public int compareTo(Version o) { int[] thisVersions = versions; int[] otherVersions = o.versions; for (int i = 0; i < Math.max(otherVersions.length, thisVersions.length); i++) { int version = i >= thisVersions.length ? 0 : thisVersions[i]; int otherVersion = i >= otherVersions.length ? 0 : otherVersions[i]; int cmp = Integer.compare(version, otherVersion); if (cmp != 0) { return cmp; } } return 0; } /** * Compares this version to another GraalVM version. This is equivalent to using: * compareTo(Version.create(compareVersions)) * . * * @since 19.3 */ public int compareTo(int... compareVersions) { return compareTo(Version.create(compareVersions)); } /** * {@inheritDoc} * * @since 19.3 */ @Override public boolean equals(Object obj) { if (!(obj instanceof Version)) { return false; } Version other = (Version) obj; return Arrays.equals(this.versions, other.versions) && this.snapshot == other.snapshot && Objects.equals(suffix, other.suffix); } /** * {@inheritDoc} * * @since 19.3 */ @Override public int hashCode() { return Objects.hash(Arrays.hashCode(this.versions), snapshot, suffix); } /** * {@inheritDoc} * * @since 19.3 */ @Override public String toString() { if (versions.length == 0) { assert suffix != null && suffix.equals(SNAPSHOT_STRING); return suffix; } StringBuilder b = new StringBuilder(); String sep = ""; for (int i = 0; i < Math.max(MIN_VERSION_DIGITS, versions.length); i++) { b.append(sep); if (i < versions.length) { b.append(versions[i]); } else { b.append(0); } sep = "."; } if (suffix != null) { b.append("-").append(suffix); } return b.toString(); } private String processFormat(String format) { StringBuilder ret = new StringBuilder(format.length()); int idx = 0; while (idx < format.length()) { char ch = format.charAt(idx++); if (ch == '%') { ch = format.charAt(idx++); if (ch == '[') { ch = format.charAt(idx++); boolean include = false; switch (ch) { case 'R': include = isRelease(); break; case 'S': include = isSnapshot(); break; default: if ('0' <= ch && ch <= '9') { int num = ch - '0'; include = versions.length >= num; } } int start = idx; idx = format.indexOf(']', start); if (idx < 0) { idx = format.length(); } if (include) { ret.append(format.substring(start, idx)); } idx++; // skip closing ] } else { ret.append('%'); ret.append(ch); } } else { ret.append(ch); } } return ret.toString(); } /** * Format the GraalVM version with a custom format string. *

* The format string can contain any of the standard conversions of {@link java.util.Formatter}. * At least four version components (possibly zero) are available as formatter arguments. *

* In addition to the standard conversions, these special conversions are available: *

    *
  • {@code "%[R...]"} includes a given part only if {@link #isRelease} *
  • {@code "%[S...]"} includes a given part only if {@link #isSnapshot} *
  • {@code "%[...]"} includes a given part only if the version contains at least * {@code } non-zero version components ({@code } can be 0 to 9) *
* *

Examples:

* *
     * Version.parse("22.3.0.1").format("%d.%d"); // returns "22.3"
     * Version.parse("22.3.0.1").format("%4$d"); // returns "1"
     * Version.parse("22.3.0.1").format("%[R%d.%d]%[Sdev]"); // returns "22.3"
     * Version.parse("22.3.0.1").format("%[2XX]"); // returns "XX"
     * Version.parse("23.0-dev").format("%3$d"); // returns "0"
     * Version.parse("23.0-dev").format("%[R%d.%d]%[Sdev]"); // returns "dev"
     * Version.parse("23.0-dev").format("%[2XX]"); // returns ""
     * 
* * @since 23.0 */ public String format(String format) { int len = versions.length; if (len < 4) { len = 4; } Object[] args = new Object[len]; int i = 0; for (int v : versions) { args[i++] = v; } for (; i < len; i++) { args[i] = 0; } return String.format(processFormat(format), args); } /** * Parses a GraalVM version from its String raw format. Throws {@link IllegalArgumentException} * if the passed string is not a valid GraalVM version. * * @since 19.3 */ public static Version parse(String versionString) throws IllegalArgumentException { Objects.requireNonNull(versionString); return new Version(versionString); } /** * Constructs a new GraalVM version from a list of version numbers. The versions must not be * null and none of the version numbers must be negative. At least one version * number must be non-zero. * * @see #compareTo(int...) * @since 19.3 */ public static Version create(int... versions) throws IllegalArgumentException { Objects.requireNonNull(versions); int[] useVersions = trimTrailingZeros(versions); if (useVersions.length == 0) { throw new IllegalArgumentException("At least one non-zero version must be specified."); } for (int i = 0; i < useVersions.length; i++) { if (useVersions[i] < 0) { throw new IllegalArgumentException("Versions must not be negative."); } } return new Version(useVersions); } /** * Returns the current GraalVM version of the installed component. Never null. * * @see HomeFinder#getVersion() * @since 19.3 */ public static Version getCurrent() { return parse(HomeFinder.getInstance().getVersion()); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy