Convert Version to Java - clusterformation part1 (#32009)

Implement buildSrc Version in java

- This allows to move all  all .java files from .groovy.
- Will prevent eclipse from tangling up in this setup
- make it possible to use Version from Java
This commit is contained in:
Alpar Torok 2018-07-13 08:35:12 +00:00 committed by GitHub
parent f174f72fee
commit 23198ea551
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 449 additions and 230 deletions

View File

@ -1,41 +0,0 @@
package org.elasticsearch.gradle;
import groovy.lang.Closure;
import org.gradle.api.GradleException;
import org.gradle.api.Task;
import org.gradle.api.tasks.Exec;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.stream.Collectors;
/**
* A wrapper around gradle's Exec task to capture output and log on error.
*/
public class LoggedExec extends Exec {
protected ByteArrayOutputStream output = new ByteArrayOutputStream();
public LoggedExec() {
if (getLogger().isInfoEnabled() == false) {
setStandardOutput(output);
setErrorOutput(output);
setIgnoreExitValue(true);
doLast(new Closure<Void>(this, this) {
public void doCall(Task it) throws IOException {
if (getExecResult().getExitValue() != 0) {
for (String line : output.toString("UTF-8").split("\\R")) {
getLogger().error(line);
}
throw new GradleException(
"Process \'" + getExecutable() + " " +
getArgs().stream().collect(Collectors.joining(" "))+
"\' finished with non-zero exit value " +
String.valueOf(getExecResult().getExitValue())
);
}
}
});
}
}
}

View File

@ -1,147 +0,0 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch 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
*
* 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.elasticsearch.gradle
import groovy.transform.Sortable
import java.util.regex.Matcher
import org.gradle.api.InvalidUserDataException
/**
* Encapsulates comparison and printing logic for an x.y.z version.
*/
@Sortable(includes=['id'])
public class Version {
final int major
final int minor
final int revision
final int id
final boolean snapshot
/**
* Suffix on the version name.
*/
final String suffix
public Version(int major, int minor, int revision,
String suffix, boolean snapshot) {
this.major = major
this.minor = minor
this.revision = revision
this.snapshot = snapshot
this.suffix = suffix
int suffixOffset = 0
if (suffix.contains("alpha")) {
suffixOffset += Integer.parseInt(suffix.substring(6))
} else if (suffix.contains("beta")) {
suffixOffset += 25 + Integer.parseInt(suffix.substring(5))
} else if (suffix.contains("rc")) {
suffixOffset += 50 + Integer.parseInt(suffix.substring(3));
}
this.id = major * 1000000 + minor * 10000 + revision * 100 + suffixOffset
}
public static Version fromString(String s) {
Matcher m = s =~ /(\d+)\.(\d+)\.(\d+)(-alpha\d+|-beta\d+|-rc\d+)?(-SNAPSHOT)?/
if (m.matches() == false) {
throw new InvalidUserDataException("Invalid version [${s}]")
}
return new Version(m.group(1) as int, m.group(2) as int,
m.group(3) as int, m.group(4) ?: '', m.group(5) != null)
}
@Override
public String toString() {
String snapshotStr = snapshot ? '-SNAPSHOT' : ''
return "${major}.${minor}.${revision}${suffix}${snapshotStr}"
}
public boolean before(Version compareTo) {
return id < compareTo.id
}
public boolean before(String compareTo) {
return before(fromString(compareTo))
}
public boolean onOrBefore(Version compareTo) {
return id <= compareTo.id
}
public boolean onOrBefore(String compareTo) {
return onOrBefore(fromString(compareTo))
}
public boolean onOrAfter(Version compareTo) {
return id >= compareTo.id
}
public boolean onOrAfter(String compareTo) {
return onOrAfter(fromString(compareTo))
}
public boolean after(Version compareTo) {
return id > compareTo.id
}
public boolean after(String compareTo) {
return after(fromString(compareTo))
}
public boolean onOrBeforeIncludingSuffix(Version otherVersion) {
if (id != otherVersion.id) {
return id < otherVersion.id
}
if (suffix == '') {
return otherVersion.suffix == ''
}
return otherVersion.suffix == '' || suffix < otherVersion.suffix
}
boolean equals(o) {
if (this.is(o)) return true
if (getClass() != o.class) return false
Version version = (Version) o
if (id != version.id) return false
if (major != version.major) return false
if (minor != version.minor) return false
if (revision != version.revision) return false
if (snapshot != version.snapshot) return false
if (suffix != version.suffix) return false
return true
}
int hashCode() {
int result
result = major
result = 31 * result + minor
result = 31 * result + revision
result = 31 * result + id
result = 31 * result + (snapshot ? 1 : 0)
result = 31 * result + (suffix != null ? suffix.hashCode() : 0)
return result
}
}

View File

@ -0,0 +1,44 @@
package org.elasticsearch.gradle;
import org.gradle.api.GradleException;
import org.gradle.api.tasks.Exec;
import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
/**
* A wrapper around gradle's Exec task to capture output and log on error.
*/
@SuppressWarnings("unchecked")
public class LoggedExec extends Exec {
protected ByteArrayOutputStream output = new ByteArrayOutputStream();
public LoggedExec() {
if (getLogger().isInfoEnabled() == false) {
setStandardOutput(output);
setErrorOutput(output);
setIgnoreExitValue(true);
doLast((unused) -> {
if (getExecResult().getExitValue() != 0) {
try {
for (String line : output.toString("UTF-8").split("\\R")) {
getLogger().error(line);
}
} catch (UnsupportedEncodingException e) {
throw new GradleException("Failed to read exec output", e);
}
throw new GradleException(
String.format(
"Process '%s %s' finished with non-zero exit value %d",
getExecutable(),
getArgs(),
getExecResult().getExitValue()
)
);
}
}
);
}
}
}

View File

@ -0,0 +1,179 @@
package org.elasticsearch.gradle;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Encapsulates comparison and printing logic for an x.y.z version.
*/
public final class Version implements Comparable<Version> {
private final int major;
private final int minor;
private final int revision;
private final int id;
private final boolean snapshot;
/**
* Suffix on the version name.
*/
private final String suffix;
private static final Pattern pattern =
Pattern.compile("(\\d)+\\.(\\d+)\\.(\\d+)(-alpha\\d+|-beta\\d+|-rc\\d+)?(-SNAPSHOT)?");
public Version(int major, int minor, int revision, String suffix, boolean snapshot) {
Objects.requireNonNull(major, "major version can't be null");
Objects.requireNonNull(minor, "minor version can't be null");
Objects.requireNonNull(revision, "revision version can't be null");
this.major = major;
this.minor = minor;
this.revision = revision;
this.snapshot = snapshot;
this.suffix = suffix == null ? "" : suffix;
int suffixOffset = 0;
if (this.suffix.isEmpty()) {
// no suffix will be considered smaller, uncomment to change that
// suffixOffset = 100;
} else {
if (this.suffix.contains("alpha")) {
suffixOffset += parseSuffixNumber(this.suffix.substring(6));
} else if (this.suffix.contains("beta")) {
suffixOffset += 25 + parseSuffixNumber(this.suffix.substring(5));
} else if (this.suffix.contains("rc")) {
suffixOffset += 50 + parseSuffixNumber(this.suffix.substring(3));
}
else {
throw new IllegalArgumentException("Suffix must contain one of: alpha, beta or rc");
}
}
// currently snapshot is not taken into account
this.id = major * 10000000 + minor * 100000 + revision * 1000 + suffixOffset * 10 /*+ (snapshot ? 1 : 0)*/;
}
private static int parseSuffixNumber(String substring) {
if (substring.isEmpty()) {
throw new IllegalArgumentException("Invalid suffix, must contain a number e.x. alpha2");
}
return Integer.parseInt(substring);
}
public static Version fromString(final String s) {
Objects.requireNonNull(s);
Matcher matcher = pattern.matcher(s);
if (matcher.matches() == false) {
throw new IllegalArgumentException(
"Invalid version format: '" + s + "'. Should be major.minor.revision[-(alpha|beta|rc)Number][-SNAPSHOT]"
);
}
return new Version(
Integer.parseInt(matcher.group(1)),
parseSuffixNumber(matcher.group(2)),
parseSuffixNumber(matcher.group(3)),
matcher.group(4),
matcher.group(5) != null
);
}
@Override
public String toString() {
final String snapshotStr = snapshot ? "-SNAPSHOT" : "";
return String.valueOf(getMajor()) + "." + String.valueOf(getMinor()) + "." + String.valueOf(getRevision()) +
(suffix == null ? "" : suffix) + snapshotStr;
}
public boolean before(Version compareTo) {
return id < compareTo.getId();
}
public boolean before(String compareTo) {
return before(fromString(compareTo));
}
public boolean onOrBefore(Version compareTo) {
return id <= compareTo.getId();
}
public boolean onOrBefore(String compareTo) {
return onOrBefore(fromString(compareTo));
}
public boolean onOrAfter(Version compareTo) {
return id >= compareTo.getId();
}
public boolean onOrAfter(String compareTo) {
return onOrAfter(fromString(compareTo));
}
public boolean after(Version compareTo) {
return id > compareTo.getId();
}
public boolean after(String compareTo) {
return after(fromString(compareTo));
}
public boolean onOrBeforeIncludingSuffix(Version otherVersion) {
if (id != otherVersion.getId()) {
return id < otherVersion.getId();
}
if (suffix.equals("")) {
return otherVersion.getSuffix().equals("");
}
return otherVersion.getSuffix().equals("") || suffix.compareTo(otherVersion.getSuffix()) < 0;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Version version = (Version) o;
return major == version.major &&
minor == version.minor &&
revision == version.revision &&
id == version.id &&
snapshot == version.snapshot &&
Objects.equals(suffix, version.suffix);
}
@Override
public int hashCode() {
return Objects.hash(major, minor, revision, id, snapshot, suffix);
}
public int getMajor() {
return major;
}
public int getMinor() {
return minor;
}
public int getRevision() {
return revision;
}
protected int getId() {
return id;
}
public boolean isSnapshot() {
return snapshot;
}
public String getSuffix() {
return suffix;
}
@Override
public int compareTo(Version other) {
return Integer.compare(getId(), other.getId());
}
}

View File

@ -1,7 +1,6 @@
package org.elasticsearch.gradle.precommit;
import groovy.lang.Closure;
import org.codehaus.groovy.runtime.ResourceGroovyMethods;
import org.elasticsearch.gradle.LoggedExec;
import org.elasticsearch.test.NamingConventionsCheck;
import org.gradle.api.GradleException;
@ -10,12 +9,12 @@ import org.gradle.api.Task;
import org.gradle.api.file.FileCollection;
import org.gradle.api.plugins.ExtraPropertiesExtension;
import org.gradle.api.plugins.JavaPluginConvention;
import org.gradle.api.tasks.AbstractExecTask;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.OutputFile;
import org.gradle.api.tasks.SourceSetContainer;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Objects;
@ -24,6 +23,7 @@ import java.util.Objects;
* tests are named according to our conventions so they'll be picked up by
* gradle. Read the Javadoc for NamingConventionsCheck to learn more.
*/
@SuppressWarnings("unchecked")
public class NamingConventionsTask extends LoggedExec {
public NamingConventionsTask() {
setDescription("Tests that test classes aren't misnamed or misplaced");
@ -31,23 +31,23 @@ public class NamingConventionsTask extends LoggedExec {
SourceSetContainer sourceSets = getJavaSourceSets();
final FileCollection classpath = project.files(
// This works because the class only depends on one class from junit that will be available from the
// tests compile classpath. It's the most straight forward way of telling Java where to find the main
// class.
NamingConventionsCheck.class.getProtectionDomain().getCodeSource().getLocation().getPath(),
// the tests to be loaded
checkForTestsInMain ? sourceSets.getByName("main").getRuntimeClasspath() : project.files(),
sourceSets.getByName("test").getCompileClasspath(),
sourceSets.getByName("test").getOutput()
// This works because the class only depends on one class from junit that will be available from the
// tests compile classpath. It's the most straight forward way of telling Java where to find the main
// class.
NamingConventionsCheck.class.getProtectionDomain().getCodeSource().getLocation().getPath(),
// the tests to be loaded
checkForTestsInMain ? sourceSets.getByName("main").getRuntimeClasspath() : project.files(),
sourceSets.getByName("test").getCompileClasspath(),
sourceSets.getByName("test").getOutput()
);
dependsOn(project.getTasks().matching(it -> "testCompileClasspath".equals(it.getName())));
getInputs().files(classpath);
setExecutable(new File(
Objects.requireNonNull(
project.getExtensions().getByType(ExtraPropertiesExtension.class).get("runtimeJavaHome")
).toString(),
"bin/java")
Objects.requireNonNull(
project.getExtensions().getByType(ExtraPropertiesExtension.class).get("runtimeJavaHome")
).toString(),
"bin/java")
);
if (checkForTestsInMain == false) {
@ -61,36 +61,34 @@ public class NamingConventionsTask extends LoggedExec {
* We build the arguments in a funny afterEvaluate/doFirst closure so that we can wait for the classpath to be
* ready for us. Strangely neither one on their own are good enough.
*/
project.afterEvaluate(new Closure<Task>(this, this) {
public Task doCall(Project it) {
return doFirst(new Closure<AbstractExecTask>(NamingConventionsTask.this, NamingConventionsTask.this) {
public AbstractExecTask doCall(Task it) {
args("-Djna.nosys=true");
args("-cp", classpath.getAsPath(), "org.elasticsearch.test.NamingConventionsCheck");
args("--test-class", getTestClass());
if (skipIntegTestInDisguise) {
args("--skip-integ-tests-in-disguise");
} else {
args("--integ-test-class", getIntegTestClass());
}
if (getCheckForTestsInMain()) {
args("--main");
args("--");
} else {
args("--");
}
return args(getExistingClassesDirs().getAsPath());
project.afterEvaluate(new Closure<Void>(this, this) {
public void doCall(Project it) {
doFirst(unused -> {
args("-Djna.nosys=true");
args("-cp", classpath.getAsPath(), "org.elasticsearch.test.NamingConventionsCheck");
args("--test-class", getTestClass());
if (skipIntegTestInDisguise) {
args("--skip-integ-tests-in-disguise");
} else {
args("--integ-test-class", getIntegTestClass());
}
if (getCheckForTestsInMain()) {
args("--main");
args("--");
} else {
args("--");
}
args(getExistingClassesDirs().getAsPath());
});
}
});
doLast(new Closure<Object>(this, this) {
public void doCall(Task it) {
try {
ResourceGroovyMethods.setText(getSuccessMarker(), "", "UTF-8");
} catch (IOException e) {
throw new GradleException("io exception", e);
doLast((Task it) -> {
try {
try (FileWriter fw = new FileWriter(getSuccessMarker())) {
fw.write("");
}
} catch (IOException e) {
throw new GradleException("io exception", e);
}
});
}
@ -101,7 +99,7 @@ public class NamingConventionsTask extends LoggedExec {
public FileCollection getExistingClassesDirs() {
FileCollection classesDirs = getJavaSourceSets().getByName(checkForTestsInMain ? "main" : "test")
.getOutput().getClassesDirs();
.getOutput().getClassesDirs();
return classesDirs.filter(it -> it.exists());
}

View File

@ -69,6 +69,10 @@ public class NamingConventionsCheck {
fail("unsupported argument '" + arg + "'");
}
}
if (rootPathList == null) {
fail("No paths provided");
return;
}
NamingConventionsCheck check = new NamingConventionsCheck(testClass, integTestClass);
for (String rootDir : rootPathList.split(Pattern.quote(File.pathSeparator))) {

View File

@ -8,7 +8,7 @@ class VersionCollectionTests extends GradleUnitTestCase {
String formatVersion(String version) {
return " public static final Version V_${version.replaceAll("\\.", "_")} "
}
def allVersions = [formatVersion('5.0.0'), formatVersion('5.0.0_alpha1'), formatVersion('5.0.0_alpha2'), formatVersion('5.0.0_beta1'),
List<String> allVersions = [formatVersion('5.0.0'), formatVersion('5.0.0_alpha1'), formatVersion('5.0.0_alpha2'), formatVersion('5.0.0_beta1'),
formatVersion('5.0.0_rc1'),formatVersion('5.0.0_rc2'),formatVersion('5.0.1'), formatVersion('5.0.2'),
formatVersion('5.1.1'), formatVersion('5.1.2'), formatVersion('5.2.0'), formatVersion('5.2.1'), formatVersion('6.0.0'),
formatVersion('6.0.1'), formatVersion('6.1.0'), formatVersion('6.1.1'), formatVersion('6.2.0'), formatVersion('6.3.0'),
@ -223,7 +223,8 @@ class VersionCollectionTests extends GradleUnitTestCase {
Version.fromString("5.1.1"), Version.fromString("5.2.0"), Version.fromString("5.2.1"),
Version.fromString("5.3.0"), Version.fromString("5.3.1")]
assertTrue(wireCompatList.containsAll(vc.wireCompatible))
List<Version> compatible = vc.wireCompatible
assertTrue(wireCompatList.containsAll(compatible))
assertTrue(vc.wireCompatible.containsAll(wireCompatList))
assertEquals(vc.snapshotsIndexCompatible.size(), 1)

View File

@ -0,0 +1,181 @@
package org.elasticsearch.gradle;
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch 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
*
* 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.
*/
import org.elasticsearch.gradle.test.GradleUnitTestCase;
import org.junit.Rule;
import org.junit.rules.ExpectedException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
public class VersionTests extends GradleUnitTestCase {
@Rule
public ExpectedException expectedEx = ExpectedException.none();
public void testVersionParsing() {
assertVersionEquals("7.0.1", 7, 0, 1, "", false);
assertVersionEquals("7.0.1-alpha2", 7, 0, 1, "-alpha2", false);
assertVersionEquals("5.1.2-rc3", 5, 1, 2, "-rc3", false);
assertVersionEquals("6.1.2-SNAPSHOT", 6, 1, 2, "", true);
assertVersionEquals("6.1.2-beta1-SNAPSHOT", 6, 1, 2, "-beta1", true);
}
public void testCompareWithStringVersions() {
assertTrue("1.10.20 is not interpreted as before 2.0.0",
Version.fromString("1.10.20").before("2.0.0")
);
assertTrue("7.0.0-alpha1 is not interpreted as before 7.0.0-alpha2",
Version.fromString("7.0.0-alpha1").before("7.0.0-alpha2")
);
assertTrue("7.0.0-alpha1 should be equal to 7.0.0-alpha1",
Version.fromString("7.0.0-alpha1").equals(Version.fromString("7.0.0-alpha1"))
);
assertTrue("7.0.0-SNAPSHOT should be equal to 7.0.0-SNAPSHOT",
Version.fromString("7.0.0-SNAPSHOT").equals(Version.fromString("7.0.0-SNAPSHOT"))
);
assertEquals(Version.fromString("5.2.1-SNAPSHOT"), Version.fromString("5.2.1-SNAPSHOT"));
}
public void testCollections() {
assertTrue(
Arrays.asList(
Version.fromString("5.2.0"), Version.fromString("5.2.1-SNAPSHOT"), Version.fromString("6.0.0"),
Version.fromString("6.0.1"), Version.fromString("6.1.0")
).containsAll(Arrays.asList(
Version.fromString("6.0.1"), Version.fromString("5.2.1-SNAPSHOT")
))
);
Set<Version> versions = new HashSet<>();
versions.addAll(Arrays.asList(
Version.fromString("5.2.0"), Version.fromString("5.2.1-SNAPSHOT"), Version.fromString("6.0.0"),
Version.fromString("6.0.1"), Version.fromString("6.1.0")
));
Set<Version> subset = new HashSet<>();
subset.addAll(Arrays.asList(
Version.fromString("6.0.1"), Version.fromString("5.2.1-SNAPSHOT")
));
assertTrue(versions.containsAll(subset));
}
public void testToString() {
assertEquals("7.0.1", new Version(7, 0, 1, null, false).toString());
}
public void testCompareVersions() {
assertEquals(0, new Version(7, 0, 0, null, true).compareTo(
new Version(7, 0, 0, null, true)
));
assertEquals(0, new Version(7, 0, 0, null, true).compareTo(
new Version(7, 0, 0, "", true)
));
// snapshot is not taken into account TODO inconsistent with equals
assertEquals(
0,
new Version(7, 0, 0, "", false).compareTo(
new Version(7, 0, 0, null, true))
);
// without sufix is smaller than with TODO
assertOrder(
new Version(7, 0, 0, null, false),
new Version(7, 0, 0, "-alpha1", false)
);
// numbered sufix
assertOrder(
new Version(7, 0, 0, "-alpha1", false),
new Version(7, 0, 0, "-alpha2", false)
);
// ranked sufix
assertOrder(
new Version(7, 0, 0, "-alpha8", false),
new Version(7, 0, 0, "-rc1", false)
);
// ranked sufix
assertOrder(
new Version(7, 0, 0, "-alpha8", false),
new Version(7, 0, 0, "-beta1", false)
);
// ranked sufix
assertOrder(
new Version(7, 0, 0, "-beta8", false),
new Version(7, 0, 0, "-rc1", false)
);
// major takes precedence
assertOrder(
new Version(6, 10, 10, "-alpha8", true),
new Version(7, 0, 0, "-alpha2", false)
);
// then minor
assertOrder(
new Version(7, 0, 10, "-alpha8", true),
new Version(7, 1, 0, "-alpha2", false)
);
// then revision
assertOrder(
new Version(7, 1, 0, "-alpha8", true),
new Version(7, 1, 10, "-alpha2", false)
);
}
public void testExceptionEmpty() {
expectedEx.expect(IllegalArgumentException.class);
expectedEx.expectMessage("Invalid version format");
Version.fromString("");
}
public void testExceptionSyntax() {
expectedEx.expect(IllegalArgumentException.class);
expectedEx.expectMessage("Invalid version format");
Version.fromString("foo.bar.baz");
}
public void testExceptionSuffixNumber() {
expectedEx.expect(IllegalArgumentException.class);
expectedEx.expectMessage("Invalid suffix");
new Version(7, 1, 1, "-alpha", true);
}
public void testExceptionSuffix() {
expectedEx.expect(IllegalArgumentException.class);
expectedEx.expectMessage("Suffix must contain one of:");
new Version(7, 1, 1, "foo1", true);
}
private void assertOrder(Version smaller, Version bigger) {
assertEquals(smaller + " should be smaller than " + bigger, -1, smaller.compareTo(bigger));
}
private void assertVersionEquals(String stringVersion, int major, int minor, int revision, String sufix, boolean snapshot) {
Version version = Version.fromString(stringVersion);
assertEquals(major, version.getMajor());
assertEquals(minor, version.getMinor());
assertEquals(revision, version.getRevision());
if (snapshot) {
assertTrue("Expected version to be a snapshot but it was not", version.isSnapshot());
} else {
assertFalse("Expected version not to be a snapshot but it was", version.isSnapshot());
}
assertEquals(sufix, version.getSuffix());
}
}