diff --git a/README.md b/README.md index 46430e8..4489f60 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ A simple wrapper around GraalVM tooling that will download and locally cache a G available select parts of the GraalVM compiler for use in Gradle builds. To use this plugin, apply `com.palantir.graal`. See a full example in the -[integration tests](src/test/groovy/com/palantir/gradle/graal/GradleGraalPluginIntegrationSpec.groovy). +[ETE tests](src/test/groovy/com/palantir/gradle/graal/GradleGraalEndToEndSpec.groovy). Gradle Tasks ------------ diff --git a/build.gradle b/build.gradle index 40b4e15..dd3b70b 100644 --- a/build.gradle +++ b/build.gradle @@ -65,6 +65,7 @@ dependencies { testCompile gradleTestKit() testCompile 'com.netflix.nebula:nebula-test' + testCompile 'com.squareup.okhttp3:mockwebserver' baseline 'com.palantir.baseline:gradle-baseline-java-config:0.26.1@zip' } @@ -95,7 +96,7 @@ tasks.withType(JavaCompile) { gradlePlugin { // do not add new task to publish to plugins.gradle.org automatedPublishing = false - + plugins { graal { id = 'com.palantir.graal' diff --git a/src/main/java/com/palantir/gradle/graal/DownloadGraalTask.java b/src/main/java/com/palantir/gradle/graal/DownloadGraalTask.java index a99ed4e..afb0d35 100644 --- a/src/main/java/com/palantir/gradle/graal/DownloadGraalTask.java +++ b/src/main/java/com/palantir/gradle/graal/DownloadGraalTask.java @@ -23,63 +23,65 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; import org.gradle.api.DefaultTask; -import org.gradle.api.internal.TaskInternal; +import org.gradle.api.file.RegularFile; +import org.gradle.api.provider.Property; import org.gradle.api.provider.Provider; -import org.gradle.api.specs.Spec; import org.gradle.api.tasks.Input; import org.gradle.api.tasks.OutputFile; import org.gradle.api.tasks.TaskAction; -/** Downloads GraalVM binaries to {@link GradleGraalPlugin#CACHE_DIR}. */ +/** Downloads GraalVM binaries. */ public class DownloadGraalTask extends DefaultTask { private static final String ARTIFACT_PATTERN = "[url]/vm-[version]/graalvm-ce-[version]-[os]-[arch].tar.gz"; private static final String FILENAME_PATTERN = "graalvm-ce-[version]-[arch].tar.gz"; - @Input private Provider graalVersion; - @Input private Provider downloadBaseUrl; + private final Property graalVersion = getProject().getObjects().property(String.class); + private final Property downloadBaseUrl = getProject().getObjects().property(String.class); + private final Property cacheDir = getProject().getObjects().property(Path.class); + + public DownloadGraalTask() { + setGroup(GradleGraalPlugin.TASK_GROUP); + setDescription("Downloads and caches GraalVM binaries."); + + onlyIf(task -> !getTgz().get().getAsFile().exists()); + } @TaskAction public final void downloadGraal() throws IOException { - Path cache = getCache(); - if (!(cache.toFile().mkdirs() || cache.toFile().exists())) { - throw new IllegalStateException( - "Unable to make cache directory, and the cache directory does not already exist: " + cache); + Path cache = getCacheSubdirectory().get(); + Files.createDirectories(cache); + try (InputStream in = new URL(render(ARTIFACT_PATTERN)).openStream()) { + Files.copy(in, getTgz().get().getAsFile().toPath(), StandardCopyOption.REPLACE_EXISTING); } - - InputStream in = new URL(render(ARTIFACT_PATTERN)).openStream(); - Files.copy(in, getOutput(), StandardCopyOption.REPLACE_EXISTING); - } - - @Override - public final String getGroup() { - return GradleGraalPlugin.TASK_GROUP; - } - - @Override - public final String getDescription() { - return "Downloads and caches GraalVM binaries."; } @OutputFile - public final Path getOutput() { - return getCache().resolve(render(FILENAME_PATTERN)); + public final Provider getTgz() { + return getProject().getLayout() + .file(getCacheSubdirectory().map(dir -> dir.resolve(render(FILENAME_PATTERN)).toFile())); } - /** Returns a lambda that prevents this task from running if the download target already exists in the cache. */ - @Override - public final Spec getOnlyIf() { - return spec -> !getOutput().toFile().exists(); + @Input + public final Provider getGraalVersion() { + return graalVersion; } - @SuppressWarnings("checkstyle:hiddenfield") - public final void configure(Provider graalVersion, Provider downloadBaseUrl) { - this.graalVersion = graalVersion; - this.downloadBaseUrl = downloadBaseUrl; + public final void setGraalVersion(Provider provider) { + graalVersion.set(provider); } - private Path getCache() { - return GradleGraalPlugin.CACHE_DIR.resolve(graalVersion.get()); + @Input + public final Provider getDownloadBaseUrl() { + return downloadBaseUrl; + } + + public final void setDownloadBaseUrl(Provider provider) { + downloadBaseUrl.set(provider); + } + + private Provider getCacheSubdirectory() { + return cacheDir.map(dir -> dir.resolve(graalVersion.get())); } private String render(String pattern) { @@ -109,4 +111,8 @@ public class DownloadGraalTask extends DefaultTask { throw new IllegalStateException("No GraalVM support for " + Platform.architecture()); } } + + final void setCacheDir(Path value) { + cacheDir.set(value); + } } diff --git a/src/main/java/com/palantir/gradle/graal/ExtractGraalTask.java b/src/main/java/com/palantir/gradle/graal/ExtractGraalTask.java index b838725..857c8c0 100644 --- a/src/main/java/com/palantir/gradle/graal/ExtractGraalTask.java +++ b/src/main/java/com/palantir/gradle/graal/ExtractGraalTask.java @@ -16,21 +16,38 @@ package com.palantir.gradle.graal; -import java.io.File; import java.nio.file.Path; import org.gradle.api.DefaultTask; -import org.gradle.api.internal.TaskInternal; +import org.gradle.api.file.Directory; +import org.gradle.api.file.DirectoryProperty; +import org.gradle.api.file.RegularFile; +import org.gradle.api.file.RegularFileProperty; +import org.gradle.api.provider.Property; import org.gradle.api.provider.Provider; -import org.gradle.api.specs.Spec; import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.InputFile; import org.gradle.api.tasks.OutputDirectory; import org.gradle.api.tasks.TaskAction; /** Extracts GraalVM tooling from downloaded tgz archive using the system's tar command. */ public class ExtractGraalTask extends DefaultTask { - @Input private Provider inputTgz; - @Input private Provider graalVersion; + private final RegularFileProperty inputTgz = newInputFile(); + private final Property graalVersion = getProject().getObjects().property(String.class); + private final DirectoryProperty outputDirectory = newOutputDirectory(); + private final Property cacheDir = getProject().getObjects().property(Path.class); + + public ExtractGraalTask() { + setGroup(GradleGraalPlugin.TASK_GROUP); + setDescription("Extracts GraalVM tooling from downloaded tgz archive using the system's tar command."); + + onlyIf(task -> !getOutputDirectory().get().getAsFile().exists()); + outputDirectory.set(graalVersion.map(v -> + getProject().getLayout().getProjectDirectory() + .dir(cacheDir.get().toFile().getAbsolutePath()) + .dir(v) + .dir("graalvm-ce-" + v))); + } @TaskAction public final void extractGraal() { @@ -41,34 +58,35 @@ public class ExtractGraalTask extends DefaultTask { // ideally this would be a CopyTask, but through Gradle 4.9 CopyTask fails to correctly extract symlinks getProject().exec(spec -> { spec.executable("tar"); - spec.args("-xzf", inputTgz.get().getAbsolutePath()); - spec.workingDir(GradleGraalPlugin.CACHE_DIR.resolve(graalVersion.get())); + spec.args("-xzf", inputTgz.get().getAsFile().getAbsolutePath()); + spec.workingDir(cacheDir.get().resolve(graalVersion.get())); }); } + @InputFile + public final Provider getInputTgz() { + return inputTgz; + } + + public final void setInputTgz(Provider value) { + this.inputTgz.set(value); + } + + @Input + public final Provider getGraalVersion() { + return graalVersion; + } + + public final void setGraalVersion(Provider provider) { + graalVersion.set(provider); + } + @OutputDirectory - public final Path getOutputDirectory() { - return GradleGraalPlugin.CACHE_DIR.resolve(graalVersion.get()).resolve("graalvm-ce-" + graalVersion.get()); + public final Provider getOutputDirectory() { + return outputDirectory; } - @Override - public final Spec getOnlyIf() { - return spec -> !getOutputDirectory().toFile().exists(); - } - - @Override - public final String getGroup() { - return GradleGraalPlugin.TASK_GROUP; - } - - @Override - public final String getDescription() { - return "Extracts GraalVM tooling from downloaded tgz archive using the system's tar command."; - } - - @SuppressWarnings("checkstyle:hiddenfield") - public final void configure(Provider inputTgz, Provider graalVersion) { - this.inputTgz = inputTgz; - this.graalVersion = graalVersion; + final void setCacheDir(Path value) { + cacheDir.set(value); } } diff --git a/src/main/java/com/palantir/gradle/graal/GraalExtension.java b/src/main/java/com/palantir/gradle/graal/GraalExtension.java index 46c1359..b14e65c 100644 --- a/src/main/java/com/palantir/gradle/graal/GraalExtension.java +++ b/src/main/java/com/palantir/gradle/graal/GraalExtension.java @@ -26,10 +26,10 @@ public class GraalExtension { private static final String DEFAULT_DOWNLOAD_BASE_URL = "https://github.com/oracle/graal/releases/download/"; private static final String DEFAULT_GRAAL_VERSION = "1.0.0-rc6"; - private Property downloadBaseUrl; - private Property graalVersion; - private Property mainClass; - private Property outputName; + private final Property downloadBaseUrl; + private final Property graalVersion; + private final Property mainClass; + private final Property outputName; public GraalExtension(Project project) { downloadBaseUrl = project.getObjects().property(String.class); @@ -86,7 +86,7 @@ public class GraalExtension { * *

Defaults to {@link #DEFAULT_GRAAL_VERSION}

*/ - public final Property getGraalVersion() { + public final Provider getGraalVersion() { return graalVersion; } diff --git a/src/main/java/com/palantir/gradle/graal/GradleGraalPlugin.java b/src/main/java/com/palantir/gradle/graal/GradleGraalPlugin.java index 10ea871..756265b 100644 --- a/src/main/java/com/palantir/gradle/graal/GradleGraalPlugin.java +++ b/src/main/java/com/palantir/gradle/graal/GradleGraalPlugin.java @@ -18,12 +18,12 @@ package com.palantir.gradle.graal; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.function.Supplier; -import javax.annotation.Nullable; +import java.util.Optional; import org.gradle.api.Plugin; import org.gradle.api.Project; -import org.gradle.api.Transformer; -import org.gradle.api.provider.Provider; +import org.gradle.api.plugins.JavaPlugin; +import org.gradle.api.tasks.TaskProvider; +import org.gradle.jvm.tasks.Jar; /** * Adds tasks to download, extract and interact with GraalVM tooling. @@ -44,61 +44,51 @@ import org.gradle.api.provider.Provider; */ public class GradleGraalPlugin implements Plugin { - /** Location to cache downloaded and extracted GraalVM tooling. */ - public static final Path CACHE_DIR = - Paths.get(System.getProperty("user.home"), ".gradle", "caches", "com.palantir.graal"); - - public static final String TASK_GROUP = "Graal"; + static final String TASK_GROUP = "Graal"; @Override public final void apply(Project project) { + project.getPluginManager().apply(JavaPlugin.class); GraalExtension extension = project.getExtensions().create("graal", GraalExtension.class, project); - DownloadGraalTask downloadGraal = project.getTasks().create( - "downloadGraalTooling", DownloadGraalTask.class, task -> { - task.configure(extension.getGraalVersion(), extension.getDownloadBaseUrl()); + Path cacheDir = Optional.ofNullable((String) project.getProperties().get("com.palantir.graal.cache.dir")) + .map(Paths::get) + .orElse(project.getGradle().getGradleUserHomeDir().toPath() + .resolve("caches") + .resolve("com.palantir.graal")); + + TaskProvider downloadGraal = project.getTasks().register( + "downloadGraalTooling", + DownloadGraalTask.class, + task -> { + task.setGraalVersion(extension.getGraalVersion()); + task.setDownloadBaseUrl(extension.getDownloadBaseUrl()); + task.setCacheDir(cacheDir); }); - ExtractGraalTask extractGraal = project.getTasks().create( - "extractGraalTooling", ExtractGraalTask.class, task -> { + TaskProvider extractGraal = project.getTasks().register( + "extractGraalTooling", + ExtractGraalTask.class, + task -> { + task.setGraalVersion(extension.getGraalVersion()); + task.setInputTgz(downloadGraal.get().getTgz()); + task.setCacheDir(cacheDir); task.dependsOn(downloadGraal); - task.configure(asProvider(() -> downloadGraal.getOutput().toFile()), extension.getGraalVersion()); }); - project.getTasks().create("nativeImage", NativeImageTask.class, task -> { - task.dependsOn(extractGraal); - task.dependsOn("jar"); - task.configure(extension.getMainClass(), extension.getOutputName(), extension.getGraalVersion()); - }); - } - - private static Provider asProvider(Supplier supplier) { - return new Provider() { - @Override - public T get() { - return supplier.get(); - } - - @Nullable - @Override - public T getOrNull() { - return supplier.get(); - } - - @Override - public T getOrElse(T other) { - return supplier.get(); - } - - @Override - public Provider map(Transformer transformer) { - return asProvider(() -> transformer.transform(get())); - } - - @Override - public boolean isPresent() { - return true; - } - }; + TaskProvider jar = project.getTasks().withType(Jar.class).named("jar"); + project.getTasks().register( + "nativeImage", + NativeImageTask.class, + task -> { + task.setMainClass(extension.getMainClass()); + task.setOutputName(extension.getOutputName()); + task.setGraalVersion(extension.getGraalVersion()); + task.setJarFile(jar.map(j -> j.getOutputs().getFiles().getSingleFile())); + task.setClasspath(project.getConfigurations().named("runtimeClasspath")); + task.setCacheDir(cacheDir); + task.dependsOn(extractGraal); + task.dependsOn(jar); + }); } } diff --git a/src/main/java/com/palantir/gradle/graal/NativeImageTask.java b/src/main/java/com/palantir/gradle/graal/NativeImageTask.java index 504bc95..2df835e 100644 --- a/src/main/java/com/palantir/gradle/graal/NativeImageTask.java +++ b/src/main/java/com/palantir/gradle/graal/NativeImageTask.java @@ -17,6 +17,8 @@ package com.palantir.gradle.graal; import java.io.File; +import java.io.IOException; +import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; @@ -25,90 +27,82 @@ import java.util.List; import java.util.Set; import java.util.stream.Collectors; import org.gradle.api.DefaultTask; +import org.gradle.api.artifacts.Configuration; +import org.gradle.api.file.RegularFile; +import org.gradle.api.file.RegularFileProperty; +import org.gradle.api.provider.Property; import org.gradle.api.provider.Provider; +import org.gradle.api.tasks.Classpath; import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.InputFile; +import org.gradle.api.tasks.InputFiles; +import org.gradle.api.tasks.OutputFile; import org.gradle.api.tasks.TaskAction; /** Runs GraalVM's native-image command with configured options and parameters. */ public class NativeImageTask extends DefaultTask { - @Input private Provider mainClass; - @Input private Provider outputName; - @Input private Provider graalVersion; + private final Property mainClass = getProject().getObjects().property(String.class); + private final Property outputName = getProject().getObjects().property(String.class); + private final Property graalVersion = getProject().getObjects().property(String.class); + private final Property classpath = getProject().getObjects().property(Configuration.class); + private final RegularFileProperty jarFile = newInputFile(); + private final RegularFileProperty outputFile = newOutputFile(); + private final Property cacheDir = getProject().getObjects().property(Path.class); + + public NativeImageTask() { + setGroup(GradleGraalPlugin.TASK_GROUP); + setDescription("Runs GraalVM's native-image command with configured options and parameters."); + + this.outputFile.set(getProject().getLayout().getBuildDirectory() + .dir("graal") + .map(d -> d.file(outputName.get()))); + + doLast(t -> { + getLogger().warn("native-image available at {} ({}MB)", + getProject().relativePath(outputFile.get().getAsFile()), + fileSizeMegabytes(outputFile.get())); + }); + } @TaskAction - public final void nativeImage() { - // TODO(rfink): declare classpath list as @Input in order to unlock incremental builds + public final void nativeImage() throws IOException { + List args = new ArrayList<>(); + args.add("-cp"); + args.add(generateClasspathArgument()); + args.add("-H:Path=" + maybeCreateOutputDirectory().getAbsolutePath()); + if (outputName.isPresent()) { + args.add("-H:Name=" + outputName.get()); + } + args.add(mainClass.get()); + getProject().exec(spec -> { - if (!mainClass.isPresent()) { - throw new IllegalArgumentException("nativeImage requires graal.mainClass to be defined."); - } - if (!graalVersion.isPresent()) { - throw new IllegalStateException("nativeImage requires graal.version to be defined."); - } - - List args = new ArrayList<>(); - args.add("-cp"); - args.add(generateClasspathArgument()); - - args.add("-H:Path=" + getOutputDirectory()); - - if (outputName.isPresent()) { - args.add("-H:Name=" + outputName.get()); - } - - args.add(mainClass.get()); - - spec.executable(getExecutable(graalVersion.get())); + spec.executable(getExecutable()); spec.args(args); }); } - @Override - public final String getGroup() { - return GradleGraalPlugin.TASK_GROUP; + private File maybeCreateOutputDirectory() throws IOException { + File directory = getOutputFile().get().getAsFile().getParentFile(); + Files.createDirectories(directory.toPath()); + return directory; } - @Override - public final String getDescription() { - return "Runs GraalVM's native-image command with configured options and parameters."; - } - - private String getOutputDirectory() { - File outputDirectory = getProject().getProjectDir().toPath().resolve(Paths.get("build", "graal")).toFile(); - - if (!(outputDirectory.mkdirs() || outputDirectory.exists())) { - throw new IllegalStateException( - "Output directory does not exist and cannot be created: " + outputDirectory); - } - - return outputDirectory.getAbsolutePath(); - } - - private String getExecutable(String version) { - return GradleGraalPlugin.CACHE_DIR - .resolve(Paths.get(version, "graalvm-ce-" + version)) + private String getExecutable() { + return cacheDir.get() + .resolve(Paths.get(graalVersion.get(), "graalvm-ce-" + graalVersion.get())) .resolve(getArchitectureSpecifiedBinaryPath()) .toFile() .getAbsolutePath(); } private String generateClasspathArgument() { - Set classpath = new LinkedHashSet<>(); - classpath.addAll(getProject().getConfigurations().getByName("runtimeClasspath").getFiles()); - classpath.addAll(getProject().getTasks().getByName("jar").getOutputs().getFiles().getFiles()); + Set classpathArgument = new LinkedHashSet<>(); - return classpath.stream() - .map(File::getAbsolutePath) - .collect(Collectors.joining(":")); - } + classpathArgument.addAll(classpath.get().getFiles()); + classpathArgument.add(jarFile.getAsFile().get()); - @SuppressWarnings("checkstyle:hiddenfield") - public final void configure(Provider mainClass, Provider outputName, - Provider graalVersion) { - this.mainClass = mainClass; - this.outputName = outputName; - this.graalVersion = graalVersion; + return classpathArgument.stream().map(File::getAbsolutePath).collect(Collectors.joining(":")); } private Path getArchitectureSpecifiedBinaryPath() { @@ -120,4 +114,66 @@ public class NativeImageTask extends DefaultTask { } } + private long fileSizeMegabytes(RegularFile regularFile) { + try { + return Files.size(regularFile.getAsFile().toPath()) / (1000 * 1000); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Input + public final Provider getMainClass() { + return mainClass; + } + + public final void setMainClass(Provider provider) { + mainClass.set(provider); + } + + @Input + public final Provider getOutputName() { + return outputName; + } + + @Input + public final Provider getGraalVersion() { + return graalVersion; + } + + public final void setGraalVersion(Provider provider) { + graalVersion.set(provider); + } + + @InputFiles + @Classpath + public final Provider getClasspath() { + return classpath; + } + + public final void setClasspath(Provider provider) { + classpath.set(provider); + } + + @InputFile + public final Provider getJarFiles() { + return jarFile; + } + + public final void setJarFile(Provider provider) { + jarFile.set(getProject().getLayout().file(provider)); + } + + @OutputFile + public final Provider getOutputFile() { + return outputFile; + } + + public final void setOutputName(Provider provider) { + outputName.set(provider); + } + + final void setCacheDir(Path value) { + cacheDir.set(value); + } } diff --git a/src/main/resources/META-INF/gradle-plugins/com.palantir.graal.properties b/src/main/resources/META-INF/gradle-plugins/com.palantir.graal.properties new file mode 100644 index 0000000..bb9dc53 --- /dev/null +++ b/src/main/resources/META-INF/gradle-plugins/com.palantir.graal.properties @@ -0,0 +1 @@ +implementation-class=com.palantir.gradle.graal.GradleGraalPlugin diff --git a/src/test/groovy/com/palantir/gradle/graal/GradleGraalEndToEndSpec.groovy b/src/test/groovy/com/palantir/gradle/graal/GradleGraalEndToEndSpec.groovy new file mode 100644 index 0000000..3a48cb9 --- /dev/null +++ b/src/test/groovy/com/palantir/gradle/graal/GradleGraalEndToEndSpec.groovy @@ -0,0 +1,80 @@ +/* + * (c) Copyright 2018 Palantir Technologies Inc. All rights reserved. + * + * 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 com.palantir.gradle.graal + +import nebula.test.IntegrationSpec +import nebula.test.functional.ExecutionResult + +class GradleGraalEndToEndSpec extends IntegrationSpec { + + def 'test default version nativeImage'() { + setup: + directory("src/main/java/com/palantir/test") + file("src/main/java/com/palantir/test/Main.java") << ''' + package com.palantir.test; + + public final class Main { + public static final void main(String[] args) { + System.out.println("hello, world!"); + } + } + ''' + + buildFile << ''' + apply plugin: 'com.palantir.graal' + + graal { + mainClass 'com.palantir.test.Main' + outputName 'hello-world' + graalVersion '1.0.0-rc5' + } + ''' + + when: + ExecutionResult result = runTasksSuccessfully('nativeImage') // note, this accesses your real ~/.gradle cache + println "Gradle Standard Out:\n" + result.standardOutput + println "Gradle Standard Error:\n" + result.standardError + File output = new File(getProjectDir(), "build/graal/hello-world"); + + then: + output.exists() + output.getAbsolutePath().execute().text.equals("hello, world!\n") + + when: + ExecutionResult result2 = runTasksSuccessfully('nativeImage') + + then: + result2.wasUpToDate(':nativeImage') + + when: + new File(getProjectDir(), "src/main/java/com/palantir/test/Main.java").text = ''' + package com.palantir.test; + + public final class Main { + public static final void main(String[] args) { + System.out.println("hello, world (modified)!"); + } + } + ''' + ExecutionResult result3 = runTasksSuccessfully('nativeImage') + + then: + println result3.standardOutput + !result3.wasUpToDate(':nativeImage') + output.getAbsolutePath().execute().text.equals("hello, world (modified)!\n") + } +} diff --git a/src/test/groovy/com/palantir/gradle/graal/GradleGraalPluginIntegrationSpec.groovy b/src/test/groovy/com/palantir/gradle/graal/GradleGraalPluginIntegrationSpec.groovy index 0745aee..be6ba74 100644 --- a/src/test/groovy/com/palantir/gradle/graal/GradleGraalPluginIntegrationSpec.groovy +++ b/src/test/groovy/com/palantir/gradle/graal/GradleGraalPluginIntegrationSpec.groovy @@ -18,12 +18,20 @@ package com.palantir.gradle.graal import nebula.test.IntegrationSpec import nebula.test.functional.ExecutionResult +import okhttp3.mockwebserver.MockResponse +import okhttp3.mockwebserver.MockWebServer +import org.junit.Rule class GradleGraalPluginIntegrationSpec extends IntegrationSpec { - def 'test default version nativeImage'() { - setup: - new File(getProjectDir(), "src/main/java/com/palantir/test").mkdirs() - new File(getProjectDir(), "src/main/java/com/palantir/test/Main.java") << ''' + + @Rule MockWebServer server = new MockWebServer() + String fakeBaseUrl + + def setup() { + fakeBaseUrl = String.format("http://localhost:%s/oracle/graal/releases/download/", server.getPort()) + + directory("src/main/java/com/palantir/test") + file("src/main/java/com/palantir/test/Main.java") << ''' package com.palantir.test; public final class Main { @@ -33,26 +41,53 @@ class GradleGraalPluginIntegrationSpec extends IntegrationSpec { } ''' - buildFile << ''' - apply plugin: 'java' + file('gradle.properties') << "com.palantir.graal.cache.dir=${getProjectDir().toPath().resolve("cacheDir").toAbsolutePath()}" + } + + def 'allows specifying different graal version'() { + setup: + buildFile << """ apply plugin: 'com.palantir.graal' graal { - mainClass 'com.palantir.test.Main' - outputName 'hello-world' + graalVersion '1.0.0-rc3' + downloadBaseUrl '${fakeBaseUrl}' } - ''' + """ + server.enqueue(new MockResponse().setBody('<>')); when: - ExecutionResult result = runTasks('nativeImage') - // capture output from Gradle runs - println "Gradle Standard Out:\n" + result.standardOutput - println "Gradle Standard Error:\n" + result.standardError - File output = new File(getProjectDir(), "build/graal/hello-world"); + ExecutionResult result = runTasksSuccessfully('downloadGraalTooling') then: - result.success - output.exists() - output.getAbsolutePath().execute().text.equals("hello, world!\n") + println result.getStandardOutput() + result.wasExecuted(':downloadGraalTooling') + !result.wasUpToDate(':downloadGraalTooling') + !result.wasSkipped(':downloadGraalTooling') + + server.takeRequest().requestUrl.toString() =~ "http://localhost:${server.port}" + + "/oracle/graal/releases/download//vm-1.0.0-rc3/graalvm-ce-1.0.0-rc3-(macos|linux)-amd64.tar.gz" + + file("cacheDir/1.0.0-rc3/graalvm-ce-1.0.0-rc3-amd64.tar.gz").text == '<>' + } + + def 'downloadGraalTooling behaves incrementally'() { + setup: + buildFile << """ + apply plugin: 'com.palantir.graal' + + graal { + downloadBaseUrl '${fakeBaseUrl}' + } + """ + server.enqueue(new MockResponse().setBody('<>')); + + when: + ExecutionResult result1 = runTasksSuccessfully('downloadGraalTooling') + ExecutionResult result2 = runTasksSuccessfully('downloadGraalTooling') + + then: + result1.wasSkipped(':downloadGraalTooling') == false + result2.wasSkipped(':downloadGraalTooling') == true } } diff --git a/src/test/groovy/com/palantir/gradle/graal/GradleGraalPluginProjectSpec.groovy b/src/test/groovy/com/palantir/gradle/graal/GradleGraalPluginProjectSpec.groovy index af51685..6e061f7 100644 --- a/src/test/groovy/com/palantir/gradle/graal/GradleGraalPluginProjectSpec.groovy +++ b/src/test/groovy/com/palantir/gradle/graal/GradleGraalPluginProjectSpec.groovy @@ -18,9 +18,6 @@ package com.palantir.gradle.graal import nebula.test.PluginProjectSpec -/** - * Tests for {@link GradleGraalPlugin}. - */ class GradleGraalPluginProjectSpec extends PluginProjectSpec { @Override diff --git a/versions.props b/versions.props index b9b3a22..68398f2 100644 --- a/versions.props +++ b/versions.props @@ -1 +1,2 @@ com.netflix.nebula:nebula-test = 6.7.1 +com.squareup.okhttp3:* = 3.11.0