Skip to content

Commit

Permalink
Wrap VersionPropertiesLoader in a BuildService to decouple build logi…
Browse files Browse the repository at this point in the history
…c projects (#78704)

By using a BuildService we can decouple the configuration of projects but keep making
expensive operations (e.g. parsing properties file or reading minimumJavaCompiler from file) only once
per build.

This bring us closer to decouple projects and get ultimatively configuration cache compliant. In
general we will bring in more BuildServices for the main build to follow along that Pattern and
ultimatevely remove usages of allprojects and subprojects in our build.
  • Loading branch information
breskeby authored Oct 7, 2021
1 parent 5823ad6 commit f16a699
Show file tree
Hide file tree
Showing 7 changed files with 141 additions and 30 deletions.
4 changes: 4 additions & 0 deletions build-conventions/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ gradlePlugin {
id = 'elasticsearch.build-tools'
implementationClass = 'org.elasticsearch.gradle.internal.conventions.BuildToolsConventionsPlugin'
}
versions {
id = 'elasticsearch.versions'
implementationClass = 'org.elasticsearch.gradle.internal.conventions.VersionPropertiesPlugin'
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

package org.elasticsearch.gradle.internal.conventions;

import org.apache.commons.io.FileUtils;
import org.gradle.api.GradleException;
import org.gradle.api.JavaVersion;
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.provider.ProviderFactory;
import org.gradle.api.services.BuildService;
import org.gradle.api.services.BuildServiceParameters;
import org.gradle.initialization.layout.BuildLayout;
import org.gradle.initialization.layout.BuildLayoutFactory;

import javax.inject.Inject;
import java.io.File;
import java.io.IOException;
import java.util.Properties;
import java.util.function.Function;

abstract class VersionPropertiesBuildService implements BuildService<VersionPropertiesBuildService.Params>, AutoCloseable {

private final Properties properties;

@Inject
public VersionPropertiesBuildService(ProviderFactory providerFactory) {
File infoPath = getParameters().getInfoPath().getAsFile().get();
try {
File propertiesInputFile = new File(infoPath, "version.properties");
properties = VersionPropertiesLoader.loadBuildSrcVersion(propertiesInputFile, providerFactory);
properties.computeIfAbsent("minimumJava", s -> resolveMinimumJavaVersion(infoPath));
} catch (IOException e) {
throw new GradleException("Cannot load VersionPropertiesBuildService", e);
}
}

private JavaVersion resolveMinimumJavaVersion(File infoPath) {
final JavaVersion minimumJavaVersion;
File minimumJavaInfoSource = new File(infoPath, "src/main/resources/minimumCompilerVersion");
try {
String versionString = FileUtils.readFileToString(minimumJavaInfoSource);
minimumJavaVersion = JavaVersion.toVersion(versionString);
} catch (IOException e) {
throw new GradleException("Cannot resolve minimum compiler version via VersionPropertiesBuildService", e);
}
return minimumJavaVersion;
}

public Properties getProperties() {
return properties;
}

@Override
public void close() throws Exception {
}

public interface Params extends BuildServiceParameters {
RegularFileProperty getInfoPath();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

package org.elasticsearch.gradle.internal.conventions;

import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.provider.Provider;
import org.gradle.initialization.layout.BuildLayout;

import javax.inject.Inject;
import java.io.File;

public class VersionPropertiesPlugin implements Plugin<Project> {

private BuildLayout buildLayout;

@Inject
VersionPropertiesPlugin(BuildLayout buildLayout) {
this.buildLayout = buildLayout;
}

@Override
public void apply(Project project) {
// Register the service if not done yet
File infoPath = new File(buildLayout.getRootDirectory(), "build-tools-internal");
Provider<VersionPropertiesBuildService> serviceProvider = project.getGradle().getSharedServices()
.registerIfAbsent("versions", VersionPropertiesBuildService.class, spec -> {
spec.getParameters().getInfoPath().set(infoPath);
});
project.getExtensions().add("versions", serviceProvider.forUseAtConfigurationTime().get().getProperties());
}
}
22 changes: 11 additions & 11 deletions build-tools-internal/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ plugins {
id 'groovy'
id 'elasticsearch.build-tools'
id 'elasticsearch.eclipse'
id 'elasticsearch.versions'
}

group = 'org.elasticsearch.gradle'

// we update the version property to reflect if we are building a snapshot or a release build
// we write this back out below to load it in the Build.java which will be shown in rest main action
// to indicate this being a snapshot build or a release build.
Properties props = VersionPropertiesLoader.loadBuildSrcVersion(project.file('version.properties'), project.getProviders())
version = props.getProperty("elasticsearch")
version = versions.getProperty("elasticsearch")

gradlePlugin {
// We already configure publication and we don't need or want the one that comes
Expand Down Expand Up @@ -169,7 +169,7 @@ gradlePlugin {
* Java version *
*****************************************************************************/

def minCompilerJava = JavaVersion.toVersion(file('src/main/resources/minimumCompilerVersion').text)
def minCompilerJava = versions.get("minimumJava")
targetCompatibility = minCompilerJava
sourceCompatibility = minCompilerJava

Expand Down Expand Up @@ -226,22 +226,22 @@ dependencies {
api 'com.avast.gradle:gradle-docker-compose-plugin:0.14.0'
api 'org.apache.maven:maven-model:3.6.2'
api 'com.networknt:json-schema-validator:1.0.36'
api "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:${props.getProperty('jackson')}"
api "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:${versions.getProperty('jackson')}"
api 'org.ow2.asm:asm:9.0'
api 'org.ow2.asm:asm-tree:9.0'
api "org.apache.httpcomponents:httpclient:${props.getProperty('httpclient')}"
api "org.apache.httpcomponents:httpcore:${props.getProperty('httpcore')}"
compileOnly "com.puppycrawl.tools:checkstyle:${props.getProperty('checkstyle')}"
api "org.apache.httpcomponents:httpclient:${versions.getProperty('httpclient')}"
api "org.apache.httpcomponents:httpcore:${versions.getProperty('httpcore')}"
compileOnly "com.puppycrawl.tools:checkstyle:${versions.getProperty('checkstyle')}"
runtimeOnly "org.elasticsearch.gradle:reaper:$version"
testImplementation "com.puppycrawl.tools:checkstyle:${props.getProperty('checkstyle')}"
testImplementation "junit:junit:${props.getProperty('junit')}"
testImplementation "com.puppycrawl.tools:checkstyle:${versions.getProperty('checkstyle')}"
testImplementation "junit:junit:${versions.getProperty('junit')}"
testImplementation 'com.github.tomakehurst:wiremock-jre8-standalone:2.23.2'
testImplementation 'org.mockito:mockito-core:1.9.5'
testImplementation "org.hamcrest:hamcrest:${props.getProperty('hamcrest')}"
testImplementation "org.hamcrest:hamcrest:${versions.getProperty('hamcrest')}"

testImplementation testFixtures("org.elasticsearch.gradle:build-tools:$version")

integTestImplementation(platform("org.junit:junit-bom:${props.getProperty('junit5')}"))
integTestImplementation(platform("org.junit:junit-bom:${versions.getProperty('junit5')}"))
integTestImplementation("org.junit.jupiter:junit-jupiter") {
because 'allows to write and run Jupiter tests'
}
Expand Down
32 changes: 13 additions & 19 deletions build-tools/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,16 @@ plugins {
id 'java-test-fixtures'
id 'elasticsearch.publish'
id 'elasticsearch.build-tools'
id 'elasticsearch.eclipse'
id 'elasticsearch.versions'
}

description = "The elasticsearch build tools"

// we update the version property to reflect if we are building a snapshot or a release build
// we write this back out below to load it in the Build.java which will be shown in rest main action
// to indicate this being a snapshot build or a release build.
Properties props = VersionPropertiesLoader.loadBuildSrcVersion(project.file('../build-tools-internal/version.properties'), project.getProviders())
def minRuntimeJava = JavaVersion.toVersion(file('../build-tools-internal/src/main/resources/minimumRuntimeVersion').text)

allprojects {
group = "org.elasticsearch.gradle"
version = props.getProperty("elasticsearch")

apply plugin: 'java'
apply plugin: 'elasticsearch.eclipse'
targetCompatibility = minRuntimeJava
sourceCompatibility = minRuntimeJava
}
group = "org.elasticsearch.gradle"
version = versions.getProperty("elasticsearch")
targetCompatibility = versions.get("minimumJava")
sourceCompatibility = versions.get("minimumJava")

gradlePlugin {
// We already configure publication and we don't need or want the one that comes
Expand Down Expand Up @@ -69,10 +60,13 @@ gradlePlugin {
}
}

// we update the version property to reflect if we are building a snapshot or a release build
// we write this back out below to load it in the Build.java which will be shown in rest main action
// to indicate this being a snapshot build or a release build.
def generateVersionProperties = tasks.register("generateVersionProperties", WriteProperties) {
outputFile = "${buildDir}/version.properties"
comment = 'Generated version properties'
properties(props)
properties(versions)
}

tasks.named("processResources").configure {
Expand Down Expand Up @@ -118,8 +112,8 @@ dependencies {
api 'org.apache.ant:ant:1.10.8'
api 'commons-io:commons-io:2.2'

testFixturesApi "junit:junit:${props.getProperty('junit')}"
testFixturesApi "com.carrotsearch.randomizedtesting:randomizedtesting-runner:${props.getProperty('randomizedrunner')}"
testFixturesApi "junit:junit:${versions.getProperty('junit')}"
testFixturesApi "com.carrotsearch.randomizedtesting:randomizedtesting-runner:${versions.getProperty('randomizedrunner')}"
testFixturesApi gradleApi()
testFixturesApi gradleTestKit()
testFixturesApi 'com.github.tomakehurst:wiremock-jre8-standalone:2.23.2'
Expand All @@ -132,7 +126,7 @@ dependencies {
because 'required as we rely on junit4 rules'
}

integTestImplementation(platform("org.junit:junit-bom:${props.getProperty('junit5')}"))
integTestImplementation(platform("org.junit:junit-bom:${versions.getProperty('junit5')}"))
integTestImplementation("org.junit.jupiter:junit-jupiter") {
because 'allows to write and run Jupiter tests'
}
Expand Down
7 changes: 7 additions & 0 deletions build-tools/reaper/build.gradle
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
plugins {
id 'java'
id 'elasticsearch.eclipse'
id 'elasticsearch.versions'
}

group = "org.elasticsearch.gradle"
version = versions.getProperty("elasticsearch")
targetCompatibility = versions.get("minimumJava")
sourceCompatibility = versions.get("minimumJava")

tasks.named("jar").configure {
archiveFileName = "${project.name}.jar"
manifest {
Expand Down
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ plugins {
id 'elasticsearch.internal-testclusters'
id 'elasticsearch.run'
id 'elasticsearch.release-tools'
id 'elasticsearch.versions'
id "com.diffplug.spotless" version "5.15.1" apply false
}

Expand Down

0 comments on commit f16a699

Please sign in to comment.