/*******************************************************************************
* Copyright (c) 2012 Pivotal Software, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Pivotal Software, Inc. - initial API and implementation
*******************************************************************************/
package org.grails.ide.eclipse.core.model;
import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Properties;
import java.util.StringTokenizer;
import org.eclipse.core.resources.IProject;
import org.grails.ide.eclipse.core.GrailsCoreActivator;
import org.grails.ide.eclipse.core.internal.GrailsNature;
/**
* An instance of this class represents a grails version number, parsed from a String.
* @author Kris De Volder
*/
public class GrailsVersion implements Comparable<GrailsVersion> {
/**
* An object suitable to represent an "unknown" grails version. This version
* is "smaller" than any known grails version.
*/
public static final GrailsVersion UNKNOWN = new GrailsVersion(null);
String versionString;
/**
* Greater than any 1.1.x version but smaller than any 1.2.x version.
*/
public static final GrailsVersion V_1_2 = new GrailsVersion("1.2");
public static final GrailsVersion V_1_3_5 = new GrailsVersion("1.3.5");
public static final GrailsVersion V_1_3_6 = new GrailsVersion("1.3.6");
public static final GrailsVersion V_1_3_7 = new GrailsVersion("1.3.7");
public static final GrailsVersion V_1_3_8 = new GrailsVersion("1.3.8");
public static final GrailsVersion BUILDSNAPHOT_2_0_2 = new GrailsVersion("2.0.2.BUILD-SNAPSHOT",
"http://hudson.grails.org/view/Grails%202.0.x/job/grails_core_2.0.x/lastStableBuild/artifact/build/distributions/grails-2.0.2.BUILD-SNAPSHOT.zip");
public static final GrailsVersion V_2_0_ = new GrailsVersion("2.0"); //Any '2.0' version *including* milestones is 'greater' than this one
public static final GrailsVersion V_2_0_0 = new GrailsVersion("2.0.0"); //Any 2.0 version *excluding* milestones is greater than this one
public static final GrailsVersion V_2_0_1 = new GrailsVersion("2.0.1");
public static final GrailsVersion V_2_0_2 = new GrailsVersion("2.0.2");
public static final GrailsVersion V_2_0_3 = new GrailsVersion("2.0.3");
public static final GrailsVersion V_2_0_4 = new GrailsVersion("2.0.4");
public static final GrailsVersion V_2_1_ = new GrailsVersion("2.1"); //Any '2.1' version *including* milestones is 'greater' than this one
public static final GrailsVersion V_2_1_0 = new GrailsVersion("2.1.0");
public static final GrailsVersion V_2_1_1 = new GrailsVersion("2.1.1");
public static final GrailsVersion V_2_1_0_revisit = V_2_1_0; // references to this constant should be reviewed when new version of Grails comes out.
public static final GrailsVersion V_2_2_ = new GrailsVersion("2.2"); //Any '2.2' version *including* milestones is 'greater' than this one
public static final GrailsVersion V_2_2_0 = new GrailsVersion("2.2.0");
public static final GrailsVersion V_2_2_1 = new GrailsVersion("2.2.1");
public static final GrailsVersion V_2_2_2 = new GrailsVersion("2.2.2");
public static final GrailsVersion V_2_2_3 = new GrailsVersion("2.2.3");
public static final GrailsVersion V_2_2_4 = new GrailsVersion("2.2.4");
// public static final GrailsVersion V_2_0_0_M1 = new GrailsVersion("2.0.0.M1");
public static final GrailsVersion V_2_0_0_M2 = new GrailsVersion("2.0.0.M2");
// public static final GrailsVersion V_2_0_0_RC1 = new GrailsVersion("2.0.0.RC1");
// public static final GrailsVersion V_2_0_0_RC2 = new GrailsVersion("2.0.0.RC2");
// public static final GrailsVersion V_2_0_0_RC3 = new GrailsVersion("2.0.0.RC3");
// public static final GrailsVersion V_2_2_2_BUILDSNAP = new GrailsVersion("2.2.2.BUILD-SNAPSHOT",
// "http://hudson.grails.org/job/grails_core_2.2.x/lastSuccessfulBuild/artifact/build/distributions/grails-2.2.2.BUILD-SNAPSHOT.zip");
public static final GrailsVersion V_2_3_ = new GrailsVersion("2.3"); //Any '2.3' version *including* milestones is 'greater' than this one
public static final GrailsVersion V_2_3_0 = new GrailsVersion("2.3.0");
public static final GrailsVersion V_2_3_0_RC1 = new GrailsVersion("2.3.0.RC1");
public static final GrailsVersion V_2_3_1 = new GrailsVersion("2.3.1");
public static final GrailsVersion V_2_3_2 = new GrailsVersion("2.3.2");
public static final GrailsVersion V_2_3_4 = new GrailsVersion("2.3.4");
public static final GrailsVersion V_2_3_5 = new GrailsVersion("2.3.5");
public static final GrailsVersion V_2_3_7 = new GrailsVersion("2.3.7");
public static final GrailsVersion V_2_3_8 = new GrailsVersion("2.3.8");
public static final GrailsVersion V_2_4_ = new GrailsVersion("2.4");
public static final GrailsVersion V_2_4_0 = new GrailsVersion("2.4.0");
public static final GrailsVersion V_2_4_1 = new GrailsVersion("2.4.1");
public static final GrailsVersion V_2_4_2 = new GrailsVersion("2.4.2");
public static final GrailsVersion V_2_4_3 = new GrailsVersion("2.4.3");
public static final GrailsVersion V_2_4_4 = new GrailsVersion("2.4.4");
public static final GrailsVersion V_2_4_0_M1 = new GrailsVersion("2.4.0.M1");
public static final GrailsVersion V_2_4_0_M2 = new GrailsVersion("2.4.0.M2");
// public static final GrailsVersion V_2_3_2_SNAPSHOT = new GrailsVersion("2.3.2.BUILD-SNAPSHOT",
// "http://hudson.grails.org/view/Grails%202.3.x/job/grails_core_2.3.x/lastStableBuild/artifact/build/distributions/grails-2.3.0.BUILD-SNAPSHOT.zip");
public static final GrailsVersion MOST_RECENT_1_3 = V_1_3_8;
//////////////////////////////////////////
//For running test with 1.3.X
// public static final GrailsVersion PREVIOUS_PREVIOUS = V_1_3_5;
// public static final GrailsVersion PREVIOUS = V_1_3_6;
// public static final GrailsVersion MOST_RECENT = V_1_3_7;
//////////////////////////////////////////
//For running test with 2.0:
// Note: These 'constants' are now initialised in GrailsTestUtilActivator to run tests with different
// GrailsVersions
public static GrailsVersion PREVIOUS_PREVIOUS = V_1_3_7;
public static GrailsVersion PREVIOUS = V_2_1_1;
public static GrailsVersion MOST_RECENT = V_2_2_4;
private int[] numbers;
private String qualifier;
private boolean parseError = false;
public static final GrailsVersion SMALLEST_SUPPORTED_VERSION = V_1_2;
private URI downloadLocation = null;
public GrailsVersion(String versionString) {
this(versionString, (URI)null);
}
public GrailsVersion(String version, String downloadLocationURI) {
this(version, uri(downloadLocationURI));
}
private static URI uri(String str) {
try {
return new URI(str);
} catch (URISyntaxException e) {
throw new Error(e);
}
}
public GrailsVersion(String versionString, URI downloadLocation) {
this.downloadLocation = downloadLocation;
if (versionString==null || versionString.equals("<unknown>")) {
this.versionString = "<unknown>";
qualifier = "";
numbers = new int[0];
} else {
this.versionString = versionString;
StringTokenizer tokenIzer = new StringTokenizer(versionString, ".");
numbers = new int[tokenIzer.countTokens()];
int i = 0;
for (; i < numbers.length;) {
String token = tokenIzer.nextToken();
try {
numbers[i] = Integer.valueOf(token);
i++;
} catch(NumberFormatException e) {
qualifier = token;
if (i!=numbers.length-1) {
parseError = true; //Only at most one qualifier is expected
}
break;
}
}
if (i < numbers.length) {
int[] copy = new int[i];
System.arraycopy(numbers, 0, copy, 0, i);
numbers = copy;
}
}
}
public URI getDownloadLocation() {
return downloadLocation;
}
@Override
public String toString() {
return getVersionString();
}
public String getVersionString() {
if (parseError) {
return "<##unparseable##>("+versionString+")";
} else {
return versionString;
}
}
public int compareTo(GrailsVersion other) {
int result = compareNoQualifier(other);
if (result==0) {
// The numeric part is the same, must consider qualifiers if any
if (this.qualifier!=null) {
if (other.qualifier!=null) {
if (this.qualifier.equals(other.qualifier)) {
return 0;
} else {
// Both have qualifiers and they are different.
if (this.qualifier.equals("BUILD-SNAPSHOT")) {
return 1;
} else if (other.qualifier.equals("BUILD-SNAPSHOT")) {
return -1;
}
return this.qualifier.compareTo(other.qualifier);
}
} else {
// Only this has qualifier
return -1; // a qualifier makes it "smaller" (version on the way towards numeric version)
}
} else {
if (other.qualifier!=null) {
//only other has qualifier
return +1;
} else {
//neither one has qualifier
return result;
}
}
} else {
//If numbers differ, qualifier doesn't matter.
return result;
}
}
private int compareNoQualifier(GrailsVersion other) {
int[] otherNumbers = other.numbers;
for (int i = 0; i < numbers.length; i++) {
if (i<otherNumbers.length) {
if (numbers[i]<otherNumbers[i]) {
return -1;
} else if (numbers[i]>otherNumbers[i]) {
return +1;
}
//This number matches, comparison requires looking at next number
} else {
//All numbers matching, but other has fewer numbers, fewer numbers is considered smaller, so "this" is greatest
return +1;
}
}
//All numbers matching, but maybe other has more numbers
if (otherNumbers.length>numbers.length) {
return -1;
} else {
return 0; // no differences found.
}
}
@Override
public boolean equals(Object obj) {
if (obj instanceof GrailsVersion) {
return this.compareTo((GrailsVersion) obj)==0;
}
return false;
}
@Override
public int hashCode() {
return versionString.hashCode();
}
/**
* Convenience method for when we are comparing some minimum required version to
* a version String.
*/
public boolean isSatisfiedBy(String versionString) {
return this.compareTo(new GrailsVersion(versionString)) <= 0;
}
/**
* Retrieve the grails version, according to the project's aplication.properties file (i.e. what does grails think
* the grails version is for this project).
*
* @return GrailsVersion, never null. Instead of null, it returns {@link GrailsVersion}.UNKNOWN if grails version
* can not be determined.
*/
public static GrailsVersion getGrailsVersion(IProject project) {
if (project!=null) {
try {
Properties props = GrailsBuildSettingsHelper.getApplicationProperties(project);
if (props!=null) {
String versionString = (String) props.get("app.grails.version");
return new GrailsVersion(versionString);
}
return UNKNOWN;
} catch (Throwable e) {
GrailsCoreActivator.log("Couldn't determine grails version for project "+project, e);
}
}
return UNKNOWN;
}
/**
* Change given project's application.properties file so it is specified to
* use this GrailsVersion
*/
public void setOn(IProject project, boolean create) throws Exception {
Properties props;
if (create) {
props = new Properties();
} else {
props = GrailsBuildSettingsHelper.getApplicationProperties(project);
}
props.put("app.grails.version", this.getVersionString());
GrailsBuildSettingsHelper.saveApplicationProperties(project, props);
}
public static GrailsVersion getGrailsVersion(File project) {
if (project!=null && GrailsNature.looksLikeGrailsProject(project)) {
try {
Properties props = GrailsBuildSettingsHelper.getApplicationProperties(project);
if (props!=null) {
String versionString = (String) props.get("app.grails.version");
return new GrailsVersion(versionString);
}
return UNKNOWN;
} catch (Throwable e) {
GrailsCoreActivator.log("Couldn't determine grails version for project "+project, e);
}
}
return UNKNOWN;
}
/**
* Retrieve grails version of the associated grails install of this project.
* I.e. what does "eclipse think" the associated Grails version is of this project.
*/
public static GrailsVersion getEclipseGrailsVersion(IProject project) {
IGrailsInstall install = GrailsCoreActivator.getDefault().getInstallManager().getGrailsInstall(project);
if (install!=null) {
return new GrailsVersion(install.getVersionString());
}
return UNKNOWN;
}
/**
* Attempts to find a Grails install, configured in the workspace, that matches this particular grails
* version. If no such install is found this method may return null.
* @return A matching Grails install or null.
*/
public IGrailsInstall getInstall() {
return GrailsCoreActivator.getDefault().getInstallManager().getInstallFor(this);
}
/**
* @return The grails version of the default grails install configured in the workspace, or {@link GrailsVersion}.UNKNOWN,
* if no Grails install is configured in the workspace.
*/
public static GrailsVersion getDefault() {
IGrailsInstall install = GrailsCoreActivator.getDefault().getInstallManager().getDefaultGrailsInstall();
if (install!=null) {
return install.getVersion();
}
return GrailsVersion.UNKNOWN;
}
public boolean isRelease() {
return !parseError && qualifier==null;
}
public boolean isSnapshot() {
if (!parseError && qualifier!=null) {
return qualifier.contains("SNAPSHOT") || qualifier.startsWith("RC1") || qualifier.startsWith("M1");
}
return false;
}
}