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

org.conqat.engine.index.shared.UnresolvedCommitDescriptor Maven / Gradle / Ivy

/*
 * Copyright (c) CQSE GmbH
 *
 * 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 org.conqat.engine.index.shared;

import java.io.Serializable;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.checkerframework.checker.nullness.qual.Nullable;
import org.conqat.lib.commons.test.IndexValueClass;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import com.google.common.base.Preconditions;

/**
 * An already parsed commit, whose branch name may still be missing, whose timestamp can be
 * Long.MAX_VALUE (corresponding to the "HEAD" commit descriptor given in service calls), and whose
 * {@link #parentIndex} is not yet resolved.
 *
 * This intermediate version of {@link CommitDescriptor} can be built from a string without access
 * to a project storage system. It can be resolved to a {@link CommitDescriptor} with
 * UnresolvedCommitDescriptorUtils.
 */
@IndexValueClass
public final class UnresolvedCommitDescriptor implements Serializable {

	private static final Pattern COMMIT_DESCRIPTOR_STRING_PATTERN = Pattern
			.compile("^(?^\\w+:)?(?(?>HEAD)|\\d+)(p(?\\d+))?$");

	/** Default branch at HEAD. */
	public static final UnresolvedCommitDescriptor DEFAULT_HEAD = new UnresolvedCommitDescriptor(null, Long.MAX_VALUE);

	private static final long serialVersionUID = 1;

	/**
	 * Description suffix for service parameters that are of type {@link UnresolvedCommitDescriptor}.
	 */
	public static final String UNRESOLVE_COMMIT_PARAMETER_DESCRIPTOR = " This parameter can be used to pass a timestamp giving the time (in milliseconds since 1970) for which the data should be provided or \"HEAD\" to refer to the most recent commit. "
			+ "This can optionally be prefixed by the name of the branch, followed by a colon (by default, we use the default branch). "
			+ "You can append a \"p1\" to resolve to the immediate parent of the most recent commit at the given branch/timestamp. "
			+ "p2 would resolve to the parent of the immediate parent and so on. In merge commits, the parent resolution considers only the first parent. "
			+ "A parameter value that uses all features would be \"master:1601637680000p1\"";

	/** The name of the branch. */
	private final String branchName;

	/**
	 * The timestamp on the branch. This can be Long.MAX_VALUE, e.g., if the commit descriptor
	 * "branch:HEAD" was given in a service call.
	 */
	private final long timestamp;

	/**
	 * Describes the commit that is "parentIndex" before the commit referenced by the given timestamp.
	 * If no parentIndex is given this field is zero.
	 *
	 * A parent index can be used to refer to a parent of the current commit. For example, the commit
	 * descriptor "master:1234p1" refers to the immediate parent of commit "master:1234".
	 */
	private final int parentIndex;

	public UnresolvedCommitDescriptor(String branchName, long timestamp) {
		this(branchName, timestamp, 0);
	}

	public UnresolvedCommitDescriptor(String branchName, long timestamp, int parentIndex) {
		Preconditions.checkArgument(parentIndex >= 0, "Parent index %d must be positive!", parentIndex);
		this.branchName = branchName;
		this.timestamp = timestamp;
		this.parentIndex = parentIndex;
	}

	/** @see #branchName */
	public @Nullable String getBranchName() {
		return branchName;
	}

	/** @see #timestamp */
	public long getTimestamp() {
		return timestamp;
	}

	/** @see #parentIndex */
	public int getParentIndex() {
		return parentIndex;
	}

	/**
	 * Returns whether the commit is the HEAD of the default branch. This is the default value if no
	 * explicit commit has been given.
	 */
	public boolean isDefaultAtHead() {
		return branchName == null && timestamp == Long.MAX_VALUE;
	}

	@JsonValue
	@Override
	public String toString() {
		StringBuilder result = new StringBuilder();
		if (branchName != null) {
			result.append(branchName);
			result.append(":");
		}

		if (timestamp == Long.MAX_VALUE) {
			result.append(CommitDescriptor.HEAD_TIMESTAMP);
		} else {
			result.append(timestamp);
		}

		if (parentIndex > 0) {
			result.append("p").append(parentIndex);
		}
		return result.toString();
	}

	/**
	 * Deserializes from a string to an unresolved commit descriptor.
	 */
	@JsonCreator
	/* package */ static @Nullable UnresolvedCommitDescriptor getInstance(String descriptorString) {
		if (descriptorString == null) {
			return null;
		}

		Matcher matcher = COMMIT_DESCRIPTOR_STRING_PATTERN.matcher(descriptorString);
		if (!matcher.matches()) {
			throw new IllegalArgumentException(
					String.format("The given string '%s' is not a valid commit descriptor", descriptorString));
		}

		String branchName = matcher.group("branchName");
		String timestampString = matcher.group("timestamp");
		String parentString = matcher.group("parent");

		long timestamp;
		if (CommitDescriptor.HEAD_TIMESTAMP.equals(timestampString)) {
			timestamp = Long.MAX_VALUE;
		} else {
			timestamp = Long.parseLong(timestampString);
		}

		int parentIndex;
		if (parentString == null) {
			parentIndex = 0;
		} else {
			parentIndex = Integer.parseInt(parentString);
		}

		return new UnresolvedCommitDescriptor(branchName, timestamp, parentIndex);
	}

	@Override
	public boolean equals(Object o) {
		if (this == o) {
			return true;
		}
		if (o == null || getClass() != o.getClass()) {
			return false;
		}
		UnresolvedCommitDescriptor that = (UnresolvedCommitDescriptor) o;
		return timestamp == that.timestamp && parentIndex == that.parentIndex
				&& Objects.equals(branchName, that.branchName);
	}

	@Override
	public int hashCode() {
		return Objects.hash(branchName, timestamp, parentIndex);
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy