Access build tools resources (#32201)

Add a buildResources 

buildResources.take('resource') writes the resources out to the filesystem so the paths can be sent int other tools.
This commit is contained in:
Alpar Torok 2018-08-10 15:03:17 +00:00 committed by GitHub
parent e49717393a
commit ef21ab8567
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 293 additions and 1 deletions

View File

@ -87,6 +87,8 @@ class BuildPlugin implements Plugin<Project> {
project.pluginManager.apply('nebula.info-scm')
project.pluginManager.apply('nebula.info-jar')
project.getTasks().create("buildResources", ExportElasticsearchBuildResourcesTask)
globalBuildInfo(project)
configureRepositories(project)
configureConfigurations(project)
@ -101,6 +103,7 @@ class BuildPlugin implements Plugin<Project> {
configureDependenciesInfo(project)
}
/** Performs checks on the build environment and prints information about the build environment. */
static void globalBuildInfo(Project project) {
if (project.rootProject.ext.has('buildChecksDone') == false) {

View File

@ -0,0 +1,114 @@
/*
* 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 org.gradle.api.DefaultTask;
import org.gradle.api.GradleException;
import org.gradle.api.file.DirectoryProperty;
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.logging.Logger;
import org.gradle.api.logging.Logging;
import org.gradle.api.tasks.Classpath;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.OutputDirectory;
import org.gradle.api.tasks.SkipWhenEmpty;
import org.gradle.api.tasks.StopExecutionException;
import org.gradle.api.tasks.TaskAction;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
/**
* Export Elasticsearch build resources to configurable paths
* <p>
* Wil overwrite existing files and create missing directories.
* Useful for resources that that need to be passed to other processes trough the filesystem or otherwise can't be
* consumed from the classpath.
*/
public class ExportElasticsearchBuildResourcesTask extends DefaultTask {
private final Logger logger = Logging.getLogger(ExportElasticsearchBuildResourcesTask.class);
private final Set<String> resources = new HashSet<>();
private DirectoryProperty outputDir;
public ExportElasticsearchBuildResourcesTask() {
outputDir = getProject().getLayout().directoryProperty(
getProject().getLayout().getBuildDirectory().dir("build-tools-exported")
);
}
@OutputDirectory
public DirectoryProperty getOutputDir() {
return outputDir;
}
@Input
@SkipWhenEmpty
public Set<String> getResources() {
return Collections.unmodifiableSet(resources);
}
@Classpath
public String getResourcesClasspath() {
// This will make sure the task is not considered up to date if the resources are changed.
logger.info("Classpath: {}", System.getProperty("java.class.path"));
return System.getProperty("java.class.path");
}
public void setOutputDir(DirectoryProperty outputDir) {
this.outputDir = outputDir;
}
public RegularFileProperty take(String resource) {
if (getState().getExecuted() || getState().getExecuting()) {
throw new GradleException("buildResources can't be configured after the task ran. " +
"Make sure task is not used after configuration time"
);
}
resources.add(resource);
return getProject().getLayout().fileProperty(outputDir.file(resource));
}
@TaskAction
public void doExport() {
if (resources.isEmpty()) {
throw new StopExecutionException();
}
resources.stream().parallel()
.forEach(resourcePath -> {
Path destination = outputDir.get().file(resourcePath).getAsFile().toPath();
try (InputStream is = getClass().getClassLoader().getResourceAsStream(resourcePath)) {
if (is == null) {
throw new GradleException("Can't export `" + resourcePath + "` from build-tools: not found");
}
Files.copy(is, destination);
} catch (IOException e) {
throw new GradleException("Can't write resource `" + resourcePath + "` to " + destination);
}
});
}
}

View File

@ -0,0 +1,89 @@
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.GradleIntegrationTestCase;
import org.gradle.testkit.runner.BuildResult;
import org.gradle.testkit.runner.GradleRunner;
public class ExportElasticsearchBuildResourcesTaskIT extends GradleIntegrationTestCase {
public static final String PROJECT_NAME = "elasticsearch-build-resources";
public void testUpToDateWithSourcesConfigured() {
GradleRunner.create()
.withProjectDir(getProjectDir(PROJECT_NAME))
.withArguments("clean", "-s")
.withPluginClasspath()
.build();
BuildResult result = GradleRunner.create()
.withProjectDir(getProjectDir(PROJECT_NAME))
.withArguments("buildResources", "-s", "-i")
.withPluginClasspath()
.build();
assertTaskSuccessfull(result, ":buildResources");
assertBuildFileExists(result, PROJECT_NAME, "build-tools-exported/checkstyle.xml");
assertBuildFileExists(result, PROJECT_NAME, "build-tools-exported/checkstyle_suppressions.xml");
result = GradleRunner.create()
.withProjectDir(getProjectDir(PROJECT_NAME))
.withArguments("buildResources", "-s", "-i")
.withPluginClasspath()
.build();
assertTaskUpToDate(result, ":buildResources");
assertBuildFileExists(result, PROJECT_NAME, "build-tools-exported/checkstyle.xml");
assertBuildFileExists(result, PROJECT_NAME, "build-tools-exported/checkstyle_suppressions.xml");
}
public void testImplicitTaskDependencyCopy() {
BuildResult result = GradleRunner.create()
.withProjectDir(getProjectDir(PROJECT_NAME))
.withArguments("clean", "sampleCopyAll", "-s", "-i")
.withPluginClasspath()
.build();
assertTaskSuccessfull(result, ":buildResources");
assertTaskSuccessfull(result, ":sampleCopyAll");
assertBuildFileExists(result, PROJECT_NAME, "sampleCopyAll/checkstyle.xml");
// This is a side effect of compile time reference
assertBuildFileExists(result, PROJECT_NAME, "sampleCopyAll/checkstyle_suppressions.xml");
}
public void testImplicitTaskDependencyInputFileOfOther() {
BuildResult result = GradleRunner.create()
.withProjectDir(getProjectDir(PROJECT_NAME))
.withArguments("clean", "sample", "-s", "-i")
.withPluginClasspath()
.build();
assertTaskSuccessfull(result, ":sample");
assertBuildFileExists(result, PROJECT_NAME, "build-tools-exported/checkstyle.xml");
assertBuildFileExists(result, PROJECT_NAME, "build-tools-exported/checkstyle_suppressions.xml");
}
public void testIncorrectUsage() {
BuildResult result = GradleRunner.create()
.withProjectDir(getProjectDir(PROJECT_NAME))
.withArguments("noConfigAfterExecution", "-s", "-i")
.withPluginClasspath()
.buildAndFail();
assertOutputContains("buildResources can't be configured after the task ran");
}
}

View File

@ -1,8 +1,13 @@
package org.elasticsearch.gradle.test;
import org.gradle.testkit.runner.BuildResult;
import org.gradle.testkit.runner.BuildTask;
import org.gradle.testkit.runner.GradleRunner;
import org.gradle.testkit.runner.TaskOutcome;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@ -15,7 +20,7 @@ public abstract class GradleIntegrationTestCase extends GradleUnitTestCase {
throw new RuntimeException("Could not find resources dir for integration tests. " +
"Note that these tests can only be ran by Gradle and are not currently supported by the IDE");
}
return new File(root, name);
return new File(root, name).getAbsoluteFile();
}
protected GradleRunner getGradleRunner(String sampleProject) {
@ -61,4 +66,47 @@ public abstract class GradleIntegrationTestCase extends GradleUnitTestCase {
}
}
protected void assertTaskSuccessfull(BuildResult result, String taskName) {
BuildTask task = result.task(taskName);
if (task == null) {
fail("Expected task `" + taskName + "` to be successful, but it did not run");
}
assertEquals(
"Expected task to be successful but it was: " + task.getOutcome() +
"\n\nOutput is:\n" + result.getOutput() ,
TaskOutcome.SUCCESS,
task.getOutcome()
);
}
protected void assertTaskUpToDate(BuildResult result, String taskName) {
BuildTask task = result.task(taskName);
if (task == null) {
fail("Expected task `" + taskName + "` to be up-to-date, but it did not run");
}
assertEquals(
"Expected task to be up to date but it was: " + task.getOutcome() +
"\n\nOutput is:\n" + result.getOutput() ,
TaskOutcome.UP_TO_DATE,
task.getOutcome()
);
}
protected void assertBuildFileExists(BuildResult result, String projectName, String path) {
Path absPath = getBuildDir(projectName).toPath().resolve(path);
assertTrue(
result.getOutput() + "\n\nExpected `" + absPath + "` to exists but it did not" +
"\n\nOutput is:\n" + result.getOutput(),
Files.exists(absPath)
);
}
protected void assertBuildFileDoesNotExists(BuildResult result, String projectName, String path) {
Path absPath = getBuildDir(projectName).toPath().resolve(path);
assertFalse(
result.getOutput() + "\n\nExpected `" + absPath + "` bo to exists but it did" +
"\n\nOutput is:\n" + result.getOutput(),
Files.exists(absPath)
);
}
}

View File

@ -0,0 +1,38 @@
plugins {
id 'elasticsearch.build'
}
ext.licenseFile = file("$buildDir/dummy/license")
ext.noticeFile = file("$buildDir/dummy/notice")
buildResources {
take 'checkstyle.xml'
}
task sampleCopyAll(type: Sync) {
/** Note: no explicit dependency. This works with tasks that use the Provider API a.k.a "Lazy Configuration" **/
from buildResources
into "$buildDir/sampleCopyAll"
}
task sample {
// This does not work, task dependencies can't be providers
// dependsOn exportBuildResources.resource('minimumRuntimeVersion')
// Nor does this, despite https://github.com/gradle/gradle/issues/3811
// dependsOn exportBuildResources.outputDir
// for now it's just
dependsOn buildResources
// we have to refference it at configuration time in order to be picked up
ext.checkstyle_suppressions = buildResources.take('checkstyle_suppressions.xml')
doLast {
println "This task is using ${file(checkstyle_suppressions)}"
}
}
task noConfigAfterExecution {
dependsOn buildResources
doLast {
println "This should cause an error because we are refferencing " +
"${buildResources.take('checkstyle_suppressions.xml')} after the `buildResources` task has ran."
}
}