package com.loopperfect.buckaroo; import com.google.common.base.Preconditions; import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.regex.Pattern; public final class SemanticVersion implements Comparable<SemanticVersion> { public final int major; public final int minor; public final int patch; private SemanticVersion(final int major, final int minor, final int patch) { Preconditions.checkArgument(major >= 0, "major version must be non-negative"); Preconditions.checkArgument(minor >= 0, "minor version must be non-negative"); Preconditions.checkArgument(patch >= 0, "patch version must be non-negative"); this.major = major; this.minor = minor; this.patch = patch; } public int compareTo(final SemanticVersion other) { int majorComparison = Integer.compare(major, other.major); if (majorComparison != 0) { return majorComparison; } int minorComparison = Integer.compare(minor, other.minor); if (minorComparison != 0) { return minorComparison; } return Integer.compare(patch, other.patch); } public String encode() { return major + "." + minor + "." + patch; } public boolean equals(final SemanticVersion other) { Preconditions.checkNotNull(other); return this == other || ((major == other.major) && (minor == other.minor) && (patch == other.patch)); } @Override public boolean equals(final Object o) { if (o == this) { return true; } if (o == null || !(o instanceof SemanticVersion)) { return false; } return equals((SemanticVersion) o); } @Override public int hashCode() { return Objects.hash(major, minor, patch); } @Override public String toString() { return major + "." + minor + "." + patch; } public static SemanticVersion of(final int major, final int minor, final int patch) { return new SemanticVersion(major, minor, patch); } public static SemanticVersion of(final int major, final int minor) { return new SemanticVersion(major, minor, 0); } public static SemanticVersion of(final int major) { return new SemanticVersion(major, 0, 0); } public static Optional<SemanticVersion> parse(final String x) { Preconditions.checkNotNull(x); final String[] parts = x.trim().split(Pattern.quote("."), -1); // -1 enables empty parts if (parts.length == 0 || parts.length > 3) { return Optional.empty(); } final List<Integer> numbers = new ArrayList<>(); for (final String part : parts) { try { numbers.add(Integer.parseUnsignedInt(part)); } catch (final NumberFormatException e) { return Optional.empty(); } } if (numbers.size() == 3) { return Optional.of(SemanticVersion.of(numbers.get(0), numbers.get(1), numbers.get(2))); } if (numbers.size() == 2) { return Optional.of(SemanticVersion.of(numbers.get(0), numbers.get(1))); } if (numbers.size() == 1) { return Optional.of(SemanticVersion.of(numbers.get(0))); } return Optional.empty(); } }