Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow to define vendor for the Daemon JVM criteria #28931

Open
wants to merge 1 commit into
base: release
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -371,4 +371,13 @@ public boolean isIbmJvm() {
return false;
}

@Nullable
public String getVendor() {
for (String vendorProperty : VENDOR_PROPERTIES) {
if (System.getProperties().containsKey(vendorProperty) && !System.getProperty(vendorProperty).isEmpty()) {
return System.getProperty(vendorProperty);
}
}
return null;
}
}
Expand Up @@ -21,13 +21,14 @@ import org.gradle.api.JavaVersion
import org.gradle.buildconfiguration.tasks.UpdateDaemonJvm
import org.gradle.integtests.fixtures.AbstractIntegrationSpec
import org.gradle.integtests.fixtures.AvailableJavaHomes
import org.gradle.integtests.fixtures.jvm.JavaToolchainFixture
import org.gradle.internal.buildconfiguration.DaemonJvmPropertiesDefaults
import org.gradle.internal.buildconfiguration.fixture.DaemonJvmPropertiesFixture
import org.gradle.internal.jvm.Jvm
import org.gradle.test.precondition.Requires
import org.gradle.test.preconditions.IntegTestPreconditions

class UpdateDaemonJvmIntegrationTest extends AbstractIntegrationSpec implements DaemonJvmPropertiesFixture {
class UpdateDaemonJvmIntegrationTest extends AbstractIntegrationSpec implements DaemonJvmPropertiesFixture, JavaToolchainFixture {

def "root project has an updateDaemonJvm task only"() {
buildFile << """
Expand Down Expand Up @@ -104,10 +105,9 @@ class UpdateDaemonJvmIntegrationTest extends AbstractIntegrationSpec implements
succeeds( "updateDaemonJvm", "--jvm-version=10000")
}

@NotYetImplemented
def "When execute updateDaemonJvm for valid vendor option Then build properties are populated with expected values"() {
when:
run "updateDaemonJvm", "--toolchain-vendor=$vendor"
run "updateDaemonJvm", "--jvm-vendor=$vendor"

then:
assertJvmCriteria(DaemonJvmPropertiesDefaults.TOOLCHAIN_VERSION, vendor)
Expand All @@ -128,33 +128,29 @@ class UpdateDaemonJvmIntegrationTest extends AbstractIntegrationSpec implements
implementation << ["VENDOR_SPECIFIC", "J9"]
}

@NotYetImplemented
def "When execute updateDaemonJvm specifying different options Then build properties are populated with expected values"() {
when:
run "updateDaemonJvm", "--jvm-version=17", "--toolchain-vendor=IBM", "--toolchain-implementation=J9"
run "updateDaemonJvm", "--jvm-version=17", "--jvm-vendor=IBM"

then:
assertJvmCriteria(JavaVersion.VERSION_17, "IBM", "J9")
assertJvmCriteria(JavaVersion.VERSION_17, "IBM")
}

@NotYetImplemented
def "When execute updateDaemonJvm specifying different options in lower case Then build properties are populated with expected values"() {
when:
run "updateDaemonJvm", "--jvm-version=17", "--toolchain-vendor=ibm", "--toolchain-implementation=j9"
run "updateDaemonJvm", "--jvm-version=17", "--jvm-vendor=ibm"

then:
assertJvmCriteria(JavaVersion.VERSION_17, "IBM", "J9")
assertJvmCriteria(JavaVersion.VERSION_17, "IBM")
}

@NotYetImplemented
def "When execute updateDaemonJvm with unexpected --toolchain-vendor option Then fails with expected exception message"() {
def "When execute updateDaemonJvm with unexpected --jvm-vendor option Then fails with expected exception message"() {
when:
fails "updateDaemonJvm", "--toolchain-vendor=unknown-vendor"
fails "updateDaemonJvm", "--jvm-vendor=unknown-vendor"

then:
failureDescriptionContains("Problem configuring option 'toolchain-vendor' on task ':updateDaemonJvm' from command line.")
failureHasCause("Cannot convert string value 'unknown-vendor' to an enum value of type 'org.gradle.internal.jvm.inspection.JvmVendor\$KnownJvmVendor' " +
"(valid case insensitive values: ADOPTIUM, ADOPTOPENJDK, AMAZON, APPLE, AZUL, BELLSOFT, GRAAL_VM, HEWLETT_PACKARD, IBM, JETBRAINS, MICROSOFT, ORACLE, SAP, TENCENT, UNKNOWN)")
failureDescriptionContains("Value 'unknown-vendor' given for toolchainVendor is an invalid Java vendor. " +
"Possible values are [ADOPTIUM, ADOPTOPENJDK, AMAZON, APPLE, AZUL, BELLSOFT, GRAAL_VM, HEWLETT_PACKARD, IBM, JETBRAINS, MICROSOFT, ORACLE, SAP, TENCENT, UNKNOWN]")
}

@NotYetImplemented
Expand All @@ -180,29 +176,31 @@ class UpdateDaemonJvmIntegrationTest extends AbstractIntegrationSpec implements
assertJvmCriteria(otherJvm.javaVersion)
}

@NotYetImplemented
def "Given defined invalid criteria When execute updateDaemonJvm with different criteria Then criteria get modified using java home"() {
def currentJvm = JavaVersion.current()

given:
writeJvmCriteria(currentJvm, "invalidVendor")
captureJavaHome()

expect:
succeeds("updateDaemonJvm", "--jvm-version=20", "--toolchain-vendor=AZUL")
succeeds("updateDaemonJvm", "--jvm-version=20", "--jvm-vendor=AZUL")
assertJvmCriteria(JavaVersion.VERSION_20, "AZUL")
assertDaemonUsedJvm(Jvm.current())
}

@NotYetImplemented
@Requires(IntegTestPreconditions.JavaHomeWithDifferentVersionAvailable)
def "Given defined valid criteria matching with local toolchain When execute updateDaemonJvm with different criteria Then criteria get modified using the expected local toolchain"() {
def otherJvm = AvailableJavaHomes.differentVersion
def otherMetadata = AvailableJavaHomes.getJvmInstallationMetadata(otherJvm)

given:
writeJvmCriteria(otherJvm.javaVersion, otherMetadata.vendor.knownVendor.name())
captureJavaHome()

expect:
succeeds("updateDaemonJvm", "--jvm-version=20", "--toolchain-vendor=AZUL")
withInstallations(otherJvm).succeeds("updateDaemonJvm", "--jvm-version=20", "--jvm-vendor=AZUL")
assertJvmCriteria(JavaVersion.VERSION_20, "AZUL")
assertDaemonUsedJvm(otherJvm)
}
}
Expand Up @@ -28,10 +28,15 @@
import org.gradle.api.tasks.options.Option;
import org.gradle.internal.buildconfiguration.DaemonJvmPropertiesDefaults;
import org.gradle.internal.buildconfiguration.tasks.UpdateDaemonJvmModifier;
import org.gradle.internal.jvm.inspection.JvmVendor;
import org.gradle.jvm.toolchain.JvmVendorSpec;
import org.gradle.jvm.toolchain.internal.DefaultJvmVendorSpec;
import org.gradle.util.internal.GUtil;
import org.gradle.util.internal.IncubationLogger;
import org.gradle.work.DisableCachingByDefault;

import javax.inject.Inject;
import java.util.Arrays;

/**
* Generates or updates the Gradle Daemon JVM criteria.
Expand All @@ -43,6 +48,9 @@
@DisableCachingByDefault(because = "Not worth caching")
@Incubating
public abstract class UpdateDaemonJvm extends DefaultTask {

private final Property<JvmVendorSpec> jvmVendorSpec = getProject().getObjects().property(JvmVendorSpec.class);

/**
* Constructor.
*
Expand All @@ -56,10 +64,15 @@ public UpdateDaemonJvm() {
@TaskAction
void generate() {
IncubationLogger.incubatingFeatureUsed("Daemon JVM criteria");

JvmVendor jvmVendor = null;
if (jvmVendorSpec.isPresent()) {
jvmVendor = JvmVendor.KnownJvmVendor.valueOf(jvmVendorSpec.get().toString()).asJvmVendor();
}
UpdateDaemonJvmModifier.updateJvmCriteria(
getPropertiesFile().get().getAsFile(),
getJvmVersion().get(),
null,
jvmVendor,
null
);
}
Expand All @@ -85,4 +98,32 @@ void generate() {
@Option(option = "jvm-version", description = "The version of the JVM required to run the Gradle Daemon.")
@Incubating
public abstract Property<JavaVersion> getJvmVersion();

/**
* The vendor of Java required to run the Gradle Daemon.
*
* @since 8.9
*/
@Input
@Optional
@Incubating
public Property<JvmVendorSpec> getJvmVendor() {
return jvmVendorSpec;
}

/**
* The vendor of Java required to run the Gradle Daemon.
*
* @since 8.9
*/
@Option(option = "jvm-vendor", description = "The vendor of Java required to run the Gradle Daemon.")
@Incubating
public void setJvmVendor(String vendor) {
try {
JvmVendor.KnownJvmVendor jvmVendor = GUtil.toEnum(JvmVendor.KnownJvmVendor.class, vendor);
jvmVendorSpec.set(DefaultJvmVendorSpec.of(jvmVendor));
} catch (Exception e) {
throw new IllegalArgumentException(String.format("Value '%s' given for %s is an invalid Java vendor. Possible values are %s", vendor, DaemonJvmPropertiesDefaults.TOOLCHAIN_VENDOR_PROPERTY, Arrays.toString(JvmVendor.KnownJvmVendor.values())));
}
}
}
Expand Up @@ -22,6 +22,7 @@ import org.gradle.integtests.fixtures.AvailableJavaHomes
import org.gradle.integtests.fixtures.jvm.JavaToolchainFixture
import org.gradle.internal.buildconfiguration.fixture.DaemonJvmPropertiesFixture
import org.gradle.internal.jvm.Jvm
import org.gradle.internal.os.OperatingSystem
import org.gradle.test.precondition.Requires
import org.gradle.test.preconditions.IntegTestPreconditions
import org.junit.Assume
Expand All @@ -47,15 +48,29 @@ class DaemonToolchainIntegrationTest extends AbstractIntegrationSpec implements
def "Given other daemon toolchain version When executing any task Then daemon jvm was set up with expected configuration"() {
given:
def otherJvm = AvailableJavaHomes.differentVersion
writeJvmCriteria(otherJvm)
writeJvmCriteria(otherJvm.javaVersion)
captureJavaHome()

expect:
withInstallations(otherJvm).succeeds("help")
assertDaemonUsedJvm(otherJvm)
}

def "Given daemon toolchain criteria that doesn't match installed ones When executing any task Then fails with the expected message"() {
@Requires(IntegTestPreconditions.JavaHomeWithDifferentVersionAvailable)
def "Given other daemon toolchain version and vendor When executing any task Then daemon jvm was set up with expected configuration"() {
given:
def otherJvm = AvailableJavaHomes.differentVersion
def otherMetadata = AvailableJavaHomes.getJvmInstallationMetadata(otherJvm)

writeJvmCriteria(otherJvm.javaVersion, otherMetadata.vendor.knownVendor.name())
captureJavaHome()

expect:
withInstallations(otherJvm).succeeds("help")
assertDaemonUsedJvm(otherJvm)
}

def "Given daemon toolchain criteria with version that doesn't match installed ones When executing any task Then fails with the expected message"() {
given:
// Java 10 is not available
def java10 = AvailableJavaHomes.getAvailableJdks(JavaVersion.VERSION_1_10)
Expand All @@ -65,6 +80,19 @@ class DaemonToolchainIntegrationTest extends AbstractIntegrationSpec implements

expect:
fails("help")
failure.assertHasDescription("Cannot find a Java installation on your machine")
failure.assertHasDescription("Cannot find a Java installation on your machine (${OperatingSystem.current()}) matching the Daemon JVM defined requirements: JVM version '10' vendor 'any'")
}

def "Given daemon toolchain criteria with version and vendor that doesn't match installed ones When executing any task Then fails with the expected message"() {
given:
// Java 10 is not available
def java10 = AvailableJavaHomes.getAvailableJdks(JavaVersion.VERSION_1_10)
Assume.assumeTrue(java10.isEmpty())
writeJvmCriteria(JavaVersion.VERSION_1_10, "ibm")
captureJavaHome()

expect:
fails("help")
failure.assertHasDescription("Cannot find a Java installation on your machine (${OperatingSystem.current()}) matching the Daemon JVM defined requirements: JVM version '10' vendor 'IBM'")
}
}
Expand Up @@ -53,7 +53,6 @@ class DaemonToolchainInvalidCriteriaIntegrationTest extends AbstractIntegrationS
failure.assertHasDescription("Value '-1' given for toolchainVersion is an invalid Java version")
}

@NotYetImplemented
def "Given unexpected toolchain vendor When execute any task Then fails with expected exception message"() {
given:
writeJvmCriteria(JavaVersion.VERSION_17, "unexpectedVendor")
Expand All @@ -62,7 +61,7 @@ class DaemonToolchainInvalidCriteriaIntegrationTest extends AbstractIntegrationS
fails 'help'

then:
failureDescriptionContains("Option toolchainVendor doesn't accept value 'unexpectedVendor'. Possible values are " +
failureDescriptionContains("Value 'unexpectedVendor' given for toolchainVendor is an invalid Java vendor. Possible values are " +
"[ADOPTIUM, ADOPTOPENJDK, AMAZON, APPLE, AZUL, BELLSOFT, GRAAL_VM, HEWLETT_PACKARD, IBM, JETBRAINS, MICROSOFT, ORACLE, SAP, TENCENT, UNKNOWN]")
}

Expand Down
Expand Up @@ -36,6 +36,7 @@
import org.gradle.internal.concurrent.CompositeStoppable;
import org.gradle.internal.concurrent.Stoppable;
import org.gradle.internal.jvm.Jvm;
import org.gradle.internal.jvm.inspection.JvmVendor;
import org.gradle.internal.jvm.inspection.JvmVersionDetector;
import org.gradle.internal.logging.console.GlobalUserInputReceiver;
import org.gradle.internal.nativeintegration.services.NativeServices;
Expand Down Expand Up @@ -193,6 +194,7 @@ static DaemonContext buildDaemonContextForCurrentProcess(DaemonRequestContext re
UUID.randomUUID().toString(),
currentProcess.getJvm().getJavaHome(),
JavaVersion.current(),
JvmVendor.KnownJvmVendor.parse(Jvm.current().getVendor()),
null, 0L, 0,
// The gradle options aren't being properly checked.
requestContext.getDaemonOpts(),
Expand Down
Expand Up @@ -16,12 +16,15 @@

package org.gradle.launcher.cli;

import org.gradle.StartParameter;
import org.gradle.TaskExecutionRequest;
import org.gradle.api.internal.StartParameterInternal;
import org.gradle.api.internal.file.FileCollectionFactory;
import org.gradle.cli.CommandLineArgumentException;
import org.gradle.cli.CommandLineParser;
import org.gradle.cli.ParsedCommandLine;
import org.gradle.initialization.layout.BuildLayoutFactory;
import org.gradle.internal.buildconfiguration.DaemonJvmPropertiesConfigurator;
import org.gradle.jvm.toolchain.internal.ToolchainConfiguration;
import org.gradle.launcher.cli.converter.BuildLayoutConverter;
import org.gradle.launcher.cli.converter.BuildOptionBackedConverter;
Expand All @@ -38,6 +41,7 @@
import javax.annotation.Nullable;
import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class BuildEnvironmentConfigurationConverter {
Expand Down Expand Up @@ -87,13 +91,21 @@ public Parameters convertParameters(ParsedCommandLine args, @Nullable File curre
DaemonParameters daemonParameters = new DaemonParameters(buildLayout, fileCollectionFactory, properties.getRequestedSystemProperties());
daemonParametersConverter.convert(args, properties.getProperties(), daemonParameters);

// This is a workaround to maintain existing behavior that allowed
// toolchain-specific properties to be specified with -P instead of -D
Map<String, String> gradlePropertiesAsSeenByToolchains = new HashMap<>();
gradlePropertiesAsSeenByToolchains.putAll(properties.getProperties());
gradlePropertiesAsSeenByToolchains.putAll(startParameter.getProjectProperties());
toolchainConfigurationBuildOptionBackedConverter.convert(args, gradlePropertiesAsSeenByToolchains, daemonParameters.getToolchainConfiguration());
daemonParameters.setRequestedJvmCriteria(properties.getDaemonJvmProperties());
try {
// This is a workaround to maintain existing behavior that allowed
// toolchain-specific properties to be specified with -P instead of -D
Map<String, String> gradlePropertiesAsSeenByToolchains = new HashMap<>();
gradlePropertiesAsSeenByToolchains.putAll(properties.getProperties());
gradlePropertiesAsSeenByToolchains.putAll(startParameter.getProjectProperties());
toolchainConfigurationBuildOptionBackedConverter.convert(args, gradlePropertiesAsSeenByToolchains, daemonParameters.getToolchainConfiguration());
daemonParameters.setRequestedJvmCriteria(properties.getDaemonJvmProperties());
} catch (Exception exception) {
// When executing updateDaemonJvm with an invalid jvm criteria the validation will be ignored
// and instead the JAVA_HOME will be used to update the daemon-jvm.properties
if (!isExecutingUpdateDaemonJvmTask(startParameter)) {
throw exception;
}
}

return new Parameters(startParameter, daemonParameters, properties);
}
Expand All @@ -104,4 +116,9 @@ public void configure(CommandLineParser parser) {
startParameterConverter.configure(parser);
daemonParametersConverter.configure(parser);
}

private boolean isExecutingUpdateDaemonJvmTask(StartParameter startParameters) {
List<TaskExecutionRequest> taskExecutionRequests = startParameters.getTaskRequests();
return taskExecutionRequests.size() == 1 && taskExecutionRequests.get(0).getArgs().contains(DaemonJvmPropertiesConfigurator.TASK_NAME);
}
}