com.linecorp.centraldogma.common.Revision Maven / Gradle / Ivy
/*
* Copyright 2017 LINE Corporation
*
* LINE Corporation 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:
*
* https://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.linecorp.centraldogma.common;
import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Objects.requireNonNull;
import java.util.regex.Pattern;
import javax.annotation.Nullable;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.linecorp.centraldogma.internal.Util;
/**
* A revision number of a {@link Commit}.
*
* A revision number is an integer which refers to a specific point of repository history.
* When a repository is created, it starts with an initial commit whose revision is {@code 1}.
* As new commits are added, each commit gets its own revision number, monotonically increasing from the
* previous commit's revision. i.e. 1, 2, 3, ...
*
*
A revision number can also be represented as a negative integer. When a revision number is negative,
* we start from {@code -1} which refers to the latest commit in repository history, which is often called
* 'HEAD' of the repository. A smaller revision number refers to the older commit. e.g. -2 refers to the
* commit before the latest commit, and so on.
*
*
A revision with a negative integer is called 'relative revision'. By contrast, a revision with
* a positive integer is called 'absolute revision'.
*/
@JsonSerialize(using = RevisionJsonSerializer.class)
@JsonDeserialize(using = RevisionJsonDeserializer.class)
public class Revision implements Comparable {
private static final Pattern REVISION_PATTERN = Pattern.compile("^-?[0-9]+(?:\\.0)?$");
/**
* Revision {@code -1}, also known as 'HEAD'.
*/
public static final Revision HEAD = new Revision(-1);
/**
* Revision {@code 1}, also known as 'INIT'.
*/
public static final Revision INIT = new Revision(1);
private final int major;
private final String text;
/**
* Creates a new instance with the specified revision number.
*/
public Revision(int major) {
if (major == 0) {
throw new IllegalArgumentException("major: 0 (expected: a non-zero integer)");
}
this.major = major;
text = generateText(major);
}
/**
* Creates a new instance.
*
* @deprecated Use {@link #Revision(int)} instead. Minor revisions are not used anymore.
*/
@Deprecated
public Revision(int major, int minor) {
this(major);
checkArgument(minor == 0, "minor: %s (expected: 0)", minor);
}
/**
* Create a new instance from a string representation. e.g. {@code "42", "-1"}
*/
public Revision(String revisionStr) {
requireNonNull(revisionStr, "revisionStr");
if ("head".equalsIgnoreCase(revisionStr) || "-1".equals(revisionStr)) {
major = HEAD.major;
} else {
if (!REVISION_PATTERN.matcher(revisionStr).matches()) {
throw illegalRevisionArgumentException(revisionStr);
}
try {
major = Integer.parseInt(
!revisionStr.endsWith(".0") ? revisionStr
: revisionStr.substring(0, revisionStr.length() - 2));
if (major == 0) {
throw illegalRevisionArgumentException(revisionStr);
}
} catch (NumberFormatException ignored) {
throw illegalRevisionArgumentException(revisionStr);
}
}
text = generateText(major);
}
/**
* Returns the revision number.
*/
public int major() {
return major;
}
/**
* Returns {@code 0}.
*
* @deprecated Do not use. Minor revisions are not used anymore.
*/
@Deprecated
public int minor() {
return 0;
}
/**
* Returns the textual representation of the revision. e.g. {@code "42", "-1"}.
*/
public String text() {
return text;
}
/**
* Returns {@code true}.
*
* @deprecated Do not use. Minor revisions are not used anymore.
*/
@Deprecated
public boolean onMainLane() {
return true;
}
/**
* Returns a new {@link Revision} whose revision number is earlier than this {@link Revision}.
*
* @param count the number of commits to go backward
*/
public Revision backward(int count) {
if (count == 0) {
return this;
}
if (count < 0) {
throw new IllegalArgumentException("count " + count + " (expected: a non-negative integer)");
}
return new Revision(subtract(major, count));
}
private static int subtract(int revNum, int delta) {
if (revNum > 0) {
return Math.max(1, revNum - delta);
} else {
if (revNum < Integer.MIN_VALUE + delta) {
return Integer.MIN_VALUE;
} else {
return revNum - delta;
}
}
}
/**
* Returns a new {@link Revision} whose revision number is later than this {@link Revision}.
*
* @param count the number of commits to go forward
*/
public Revision forward(int count) {
if (count == 0) {
return this;
}
if (count < 0) {
throw new IllegalArgumentException("count " + count + " (expected: a non-negative integer)");
}
return new Revision(add(major, count));
}
private static int add(int revNum, int delta) {
if (revNum > 0) {
if (revNum > Integer.MAX_VALUE - delta) {
return Integer.MAX_VALUE;
} else {
return revNum + delta;
}
} else {
return Math.min(-1, revNum + delta);
}
}
@Override
public int hashCode() {
return major;
}
@Override
public boolean equals(@Nullable Object o) {
if (this == o) {
return true;
}
if (!(o instanceof Revision)) {
return false;
}
return major == ((Revision) o).major;
}
@Override
public String toString() {
final StringBuilder buf = new StringBuilder();
buf.append(Util.simpleTypeName(this));
buf.append('(');
buf.append(major);
buf.append(')');
return buf.toString();
}
@Override
public int compareTo(Revision o) {
return Integer.compare(major, o.major);
}
/**
* Returns whether this {@link Revision} is relative.
*/
public boolean isRelative() {
return major < 0;
}
private static String generateText(int major) {
return String.valueOf(major);
}
private static IllegalArgumentException illegalRevisionArgumentException(String revisionStr) {
return new IllegalArgumentException(
"revisionStr: " + revisionStr +
" (expected: \"major\" or \"major.0\" where major is non-zero integer)");
}
}