/*
* Copyright 2017 the original author or authors.
*
* 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 sagan.projects;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import org.springframework.util.Assert;
import sagan.projects.support.Version;
import javax.persistence.CascadeType;
import javax.persistence.Embeddable;
import javax.persistence.ManyToOne;
import java.util.regex.Pattern;
@Embeddable
@JsonInclude(Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public class ProjectRelease implements Comparable<ProjectRelease> {
private static final Pattern PRERELEASE_PATTERN = Pattern.compile("[A-Za-z0-9\\.\\-]+?(M|RC)\\d+");
private static final String SNAPSHOT_SUFFIX = "SNAPSHOT";
private static final String VERSION_PLACEHOLDER = "{version}";
private static final String VERSION_PATTERN = Pattern.quote(VERSION_PLACEHOLDER);
public enum ReleaseStatus {
SNAPSHOT, PRERELEASE, GENERAL_AVAILABILITY;
public static ReleaseStatus getFromVersion(String version) {
Assert.notNull(version, "Version must not be null");
if (version.endsWith(SNAPSHOT_SUFFIX)) {
return SNAPSHOT;
}
if (PRERELEASE_PATTERN.matcher(version).matches()) {
return PRERELEASE;
}
return GENERAL_AVAILABILITY;
}
}
private String versionName;
private ReleaseStatus releaseStatus;
private boolean isCurrent;
private String refDocUrl;
private String apiDocUrl;
private String groupId;
private String artifactId;
@ManyToOne(cascade = { CascadeType.PERSIST, CascadeType.MERGE })
private ProjectRepository repository;
public ProjectRelease() {
}
public ProjectRelease(String versionName, ReleaseStatus releaseStatus, boolean isCurrent, String refDocUrl,
String apiDocUrl, String groupId, String artifactId) {
setVersion(versionName);
if (releaseStatus != null) {
this.releaseStatus = releaseStatus;
}
this.isCurrent = isCurrent;
this.refDocUrl = refDocUrl;
this.apiDocUrl = apiDocUrl;
this.groupId = groupId;
this.artifactId = artifactId;
repository = ProjectRepository.get(versionName, this.releaseStatus);
}
public boolean isCurrent() {
return isCurrent;
}
public boolean isGeneralAvailability() {
return releaseStatus == ReleaseStatus.GENERAL_AVAILABILITY;
}
public boolean isPreRelease() {
return releaseStatus == ReleaseStatus.PRERELEASE;
}
public boolean isSnapshot() {
return releaseStatus == ReleaseStatus.SNAPSHOT;
}
public ReleaseStatus getReleaseStatus() {
return releaseStatus;
}
public String getVersion() {
return versionName;
}
public String getVersionDisplayName() {
return getVersionDisplayName(true);
}
public String getVersionDisplayName(boolean includePreReleaseDescription) {
String versionNumber = versionName;
String versionLabel = "";
if (versionName.contains(".")) {
versionNumber = versionName.substring(0, versionName.lastIndexOf("."));
versionLabel = " " + versionName.substring(versionName.lastIndexOf(".") + 1);
if (versionLabel.contains("SNAPSHOT") || versionLabel.equals(" RELEASE")) {
versionLabel = "";
}
}
return versionNumber + versionLabel;
}
public String getRefDocUrl() {
return refDocUrl;
}
public boolean hasRefDocUrl() {
return !refDocUrl.isEmpty();
}
public String getApiDocUrl() {
return apiDocUrl;
}
public boolean hasApiDocUrl() {
return !apiDocUrl.isEmpty();
}
public String getGroupId() {
return groupId;
}
public String getArtifactId() {
return artifactId;
}
public ProjectRepository getRepository() {
return repository;
}
public void setVersion(String versionName) {
this.releaseStatus = ReleaseStatus.getFromVersion(versionName);
repository = ProjectRepository.get(versionName, this.releaseStatus);
this.versionName = versionName;
}
public void setReleaseStatus(ReleaseStatus releaseStatus) {
this.releaseStatus = releaseStatus;
}
public void setCurrent(boolean isCurrent) {
this.isCurrent = isCurrent;
}
public void setRefDocUrl(String refDocUrl) {
this.refDocUrl = refDocUrl;
}
public void setApiDocUrl(String apiDocUrl) {
this.apiDocUrl = apiDocUrl;
}
public void setGroupId(String groupId) {
this.groupId = groupId;
}
public void setArtifactId(String artifactId) {
this.artifactId = artifactId;
}
public void setRepository(ProjectRepository repository) {
this.repository = repository;
}
public void replaceVersionPattern() {
String version = getVersion();
setApiDocUrl(getApiDocUrl().replaceAll(VERSION_PATTERN, version));
setRefDocUrl(getRefDocUrl().replaceAll(VERSION_PATTERN, version));
}
public ProjectRelease createWithVersionPattern() {
String version = getVersion();
ProjectRelease release = new ProjectRelease(version, releaseStatus, isCurrent, refDocUrl, apiDocUrl, groupId,
artifactId);
release.setApiDocUrl(getApiDocUrl().replaceAll(version, VERSION_PLACEHOLDER));
release.setRefDocUrl(getRefDocUrl().replaceAll(version, VERSION_PLACEHOLDER));
return release;
}
/**
* Adapted from Gradle's StaticVersionComparator
*/
@Override
public int compareTo(ProjectRelease other) {
if (other == null) {
return -1;
}
Version thisVersion = Version.build(getVersion());
Version otherVersion = Version.build(other.getVersion());
if (thisVersion == null && otherVersion == null) {
return 0;
} else if (thisVersion == null) {
return -1;
} else if (otherVersion == null) {
return 1;
}
if (thisVersion.equals(otherVersion)) {
return 0;
}
String[] theseParts = thisVersion.getParts();
String[] otherParts = otherVersion.getParts();
int i = 0;
for (; i < theseParts.length && i < otherParts.length; i++) {
if (theseParts[i].equals(otherParts[i])) {
continue;
}
boolean is1Number = isNumber(theseParts[i]);
boolean is2Number = isNumber(otherParts[i]);
if (is1Number && !is2Number) {
return 1;
}
if (is2Number && !is1Number) {
return -1;
}
if (is1Number) {
return Long.valueOf(theseParts[i]).compareTo(Long.valueOf(otherParts[i]));
}
// both are strings, we compare them lexicographically
return theseParts[i].compareTo(otherParts[i]);
}
if (i < theseParts.length) {
return isNumber(theseParts[i]) ? 1 : -1;
}
if (i < otherParts.length) {
return isNumber(otherParts[i]) ? -1 : 1;
}
return 0;
}
private boolean isNumber(String str) {
return str.matches("\\d+");
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || !(o instanceof ProjectRelease))
return false;
ProjectRelease that = (ProjectRelease) o;
if (!versionName.equals(that.versionName))
return false;
return true;
}
@Override
public int hashCode() {
return versionName.hashCode();
}
@Override
public String toString() {
return "ProjectRelease{" + "versionName='" + versionName + '\'' + ", release=" + releaseStatus
+ ", refDocUrl='" + refDocUrl + '\'' + ", apiDocUrl='" + apiDocUrl + '\'' + '}';
}
}