com.azure.core.implementation.SemanticVersion Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of azure-core Show documentation
Show all versions of azure-core Show documentation
This package contains core types for Azure Java clients.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
package com.azure.core.implementation;
import com.azure.core.util.CoreUtils;
import java.io.IOException;
import java.util.Objects;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
/**
* Implements lightweight semantic version based on https://semver.org/ for internal use.
*/
public final class SemanticVersion implements Comparable {
/**
* Represents unknown version - either invalid or missing.
*/
public static final String UNKNOWN_VERSION = "unknown";
private final int major;
private final int minor;
private final int patch;
private final String prerelease;
private final String versionString;
/**
* Returns implementation version of the package for given class. If version can't be retrieved or parsed, returns invalid version.
*
* @param className - class name to get package version of.
* @return parsed {@link SemanticVersion} or invalid one.
*/
public static SemanticVersion getPackageVersionForClass(String className) {
try {
return getPackageVersion(Class.forName(className));
} catch (Exception ignored) {
return SemanticVersion.createInvalid();
}
}
/**
* Parses semver 2.0.0 string. If version can't be retrieved or parsed, returns invalid version.
*
* @param version to parse.
* @return parsed {@link SemanticVersion} or invalid one.
*/
public static SemanticVersion parse(String version) {
Objects.requireNonNull(version, "'version' cannot be null.");
int majorDotIdx = version.indexOf('.');
if (majorDotIdx < 0) {
return createInvalid(version);
}
int minorDotIdx = version.indexOf('.', majorDotIdx + 1);
if (minorDotIdx < 0) {
return createInvalid(version);
}
int patchEndIdx = minorDotIdx + 1;
while (patchEndIdx < version.length()) {
char ch = version.charAt(patchEndIdx);
// accommodate common broken semantic versions (e.g. 1.2.3.4)
if (ch == '.' || ch == '-' || ch == '+') {
break;
}
patchEndIdx++;
}
int extEndIdx = version.indexOf('+', patchEndIdx);
if (extEndIdx < 0) {
extEndIdx = version.length();
}
try {
int major = Integer.parseInt(version.substring(0, majorDotIdx));
int minor = Integer.parseInt(version.substring(majorDotIdx + 1, minorDotIdx));
int patch = Integer.parseInt(version.substring(minorDotIdx + 1, patchEndIdx));
String prerelease = (patchEndIdx == extEndIdx) ? "" : version.substring(patchEndIdx + 1, extEndIdx);
return new SemanticVersion(major, minor, patch, prerelease, version);
} catch (NumberFormatException | NullPointerException ignored) {
return createInvalid(version);
}
}
/**
* Returns implementation version of the package for given class.
*
* @param clazz - class to get package version of.
* @return parsed {@link SemanticVersion} or invalid one.
*/
private static SemanticVersion getPackageVersion(Class> clazz) {
Objects.requireNonNull(clazz, "'clazz' cannot be null.");
if (clazz.getPackage() == null) {
return createInvalid();
}
String versionStr = clazz.getPackage().getImplementationVersion();
if (versionStr != null) {
return parse(versionStr);
}
// if versionStr is null, try loading the version from the manifest in the jar file
try (JarFile jar = new JarFile(clazz.getProtectionDomain().getCodeSource().getLocation().getFile())) {
Manifest manifest = jar.getManifest();
versionStr = manifest.getMainAttributes().getValue("Implementation-Version");
if (versionStr == null) {
versionStr = manifest.getMainAttributes().getValue("Bundle-Version");
}
return parse(versionStr);
} catch (IOException | SecurityException ignored) {
return createInvalid();
}
}
/**
* Creates invalid semantic version.
* @return instance of invalid semantic version.
*/
public static SemanticVersion createInvalid() {
return createInvalid(UNKNOWN_VERSION);
}
/**
* Creates invalid semantic version.
*/
private static SemanticVersion createInvalid(String version) {
return new SemanticVersion(-1, -1, -1, null, version);
}
/**
* Creates semantic version.
*
* @param major major version.
* @param minor minor version.
* @param patch patch version.
* @param prerelease extensions (including '-' or '+' separator after patch).
* @param versionString full version string.
*/
SemanticVersion(int major, int minor, int patch, String prerelease, String versionString) {
Objects.requireNonNull(versionString, "'versionString' cannot be null.");
this.major = major;
this.minor = minor;
this.patch = patch;
this.prerelease = prerelease;
this.versionString = versionString;
}
/**
* Returns full version string that was used to create this {@code SemanticVersion}
*
* @return original version string.
*/
public String getVersionString() {
return versionString;
}
/**
* Returns major version component or -1 for invalid version.
*
* @return major version.
*/
public int getMajorVersion() {
return major;
}
/**
* {@inheritDoc}
*/
@Override
public int compareTo(SemanticVersion other) {
if (this == other) {
return 0;
}
if (other == null) {
return -1;
}
if (major != other.major) {
return major > other.major ? 1 : -1;
}
if (minor != other.minor) {
return minor > other.minor ? 1 : -1;
}
if (patch != other.patch) {
return patch > other.patch ? 1 : -1;
}
if (CoreUtils.isNullOrEmpty(prerelease)) {
return CoreUtils.isNullOrEmpty(other.prerelease) ? 0 : 1;
}
if (CoreUtils.isNullOrEmpty(other.prerelease)) {
return -1;
}
return prerelease.compareTo(other.prerelease);
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof SemanticVersion)) {
return false;
}
SemanticVersion otherVer = (SemanticVersion) other;
return versionString.equals(otherVer.versionString);
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
return versionString.hashCode();
}
@Override
public String toString() {
return versionString;
}
/**
* Returns flag indicating if version is valid.
*
* @return true if version is valid, false otherwise.
*/
public boolean isValid() {
return this.major >= 0;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy