From 751f255f39bcda28f9846df22cef6a0710255bc1 Mon Sep 17 00:00:00 2001 From: Sterling Greene Date: Tue, 22 Nov 2022 12:49:53 -0500 Subject: [PATCH 01/17] Refactor ArtifactSelector to avoid capturing the full component metadata in the lambda --- .../resolve/resolver/DefaultArtifactSelector.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/subprojects/dependency-management/src/main/java/org/gradle/internal/resolve/resolver/DefaultArtifactSelector.java b/subprojects/dependency-management/src/main/java/org/gradle/internal/resolve/resolver/DefaultArtifactSelector.java index 3e0adfb57856..2e2bcba578b8 100644 --- a/subprojects/dependency-management/src/main/java/org/gradle/internal/resolve/resolver/DefaultArtifactSelector.java +++ b/subprojects/dependency-management/src/main/java/org/gradle/internal/resolve/resolver/DefaultArtifactSelector.java @@ -67,9 +67,11 @@ public ArtifactSet resolveArtifacts(LocalFileDependencyMetadata fileDependencyMe @Override public ArtifactSet resolveArtifacts(ComponentResolveMetadata component, @Nullable Map resolvedVariantCache, Supplier> allVariants, Set legacyVariants, ExcludeSpec exclusions, ImmutableAttributes overriddenAttributes) { + ModuleVersionIdentifier moduleVersionId = component.getModuleVersionId(); + ModuleSources sources = component.getSources(); - ImmutableSet legacyResolvedVariants = buildResolvedVariants(component, legacyVariants, exclusions, resolvedVariantCache); - ComponentArtifactResolveVariantState componentArtifactResolveVariantState = () -> buildResolvedVariants(component, allVariants.get(), exclusions, resolvedVariantCache); + ImmutableSet legacyResolvedVariants = buildResolvedVariants(moduleVersionId, sources, legacyVariants, exclusions, resolvedVariantCache); + ComponentArtifactResolveVariantState componentArtifactResolveVariantState = () -> buildResolvedVariants(moduleVersionId, sources, allVariants.get(), exclusions, resolvedVariantCache); for (OriginArtifactSelector selector : selectors) { ArtifactSet artifacts = selector.resolveArtifacts(component, componentArtifactResolveVariantState, legacyResolvedVariants, exclusions, overriddenAttributes); @@ -80,10 +82,10 @@ public ArtifactSet resolveArtifacts(ComponentResolveMetadata component, @Nullabl throw new IllegalStateException("No artifacts selected."); } - private ImmutableSet buildResolvedVariants(ComponentResolveMetadata component, Set allVariants, ExcludeSpec exclusions, @Nullable Map resolvedVariantCache) { + private ImmutableSet buildResolvedVariants(ModuleVersionIdentifier moduleVersionId, ModuleSources sources, Set allVariants, ExcludeSpec exclusions, @Nullable Map resolvedVariantCache) { ImmutableSet.Builder resolvedVariantBuilder = ImmutableSet.builder(); for (VariantResolveMetadata variant : allVariants) { - ResolvedVariant resolvedVariant = toResolvedVariant(variant.getIdentifier(), variant.asDescribable(), variant.getAttributes(), variant.getArtifacts(), variant.getCapabilities(), exclusions, component.getModuleVersionId(), component.getSources(), resolvedVariantCache); + ResolvedVariant resolvedVariant = toResolvedVariant(variant.getIdentifier(), variant.asDescribable(), variant.getAttributes(), variant.getArtifacts(), variant.getCapabilities(), exclusions, moduleVersionId, sources, resolvedVariantCache); resolvedVariantBuilder.add(resolvedVariant); } return resolvedVariantBuilder.build(); From bd1a51d158c9d900bcf6c3073e671f57e4ed5301 Mon Sep 17 00:00:00 2001 From: Sterling Greene Date: Tue, 22 Nov 2022 14:29:31 -0500 Subject: [PATCH 02/17] Attempt to reduce GC pressure by not holding expensive this references in ThreadLocals --- .../exceptions/DefaultMultiCauseException.java | 14 ++++++++------ .../gradle/api/internal/DefaultMutationGuard.java | 5 +++-- .../model/internal/registry/RuleContext.java | 7 +------ 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/subprojects/base-services/src/main/java/org/gradle/internal/exceptions/DefaultMultiCauseException.java b/subprojects/base-services/src/main/java/org/gradle/internal/exceptions/DefaultMultiCauseException.java index 1535ce97d96e..b97172eea4a0 100644 --- a/subprojects/base-services/src/main/java/org/gradle/internal/exceptions/DefaultMultiCauseException.java +++ b/subprojects/base-services/src/main/java/org/gradle/internal/exceptions/DefaultMultiCauseException.java @@ -74,12 +74,14 @@ private void writeObject(java.io.ObjectOutputStream out) throws IOException { } private ThreadLocal threadLocal() { - return new ThreadLocal() { - @Override - protected Boolean initialValue() { - return false; - } - }; + return new HideStacktrace(); + } + + private static class HideStacktrace extends ThreadLocal { + @Override + protected Boolean initialValue() { + return false; + } } @Override diff --git a/subprojects/core/src/main/java/org/gradle/api/internal/DefaultMutationGuard.java b/subprojects/core/src/main/java/org/gradle/api/internal/DefaultMutationGuard.java index c6e0a4804b7c..d512e31cc4a6 100644 --- a/subprojects/core/src/main/java/org/gradle/api/internal/DefaultMutationGuard.java +++ b/subprojects/core/src/main/java/org/gradle/api/internal/DefaultMutationGuard.java @@ -19,12 +19,13 @@ import org.gradle.api.Action; public class DefaultMutationGuard extends AbstractMutationGuard { - private final ThreadLocal mutationGuardState = new ThreadLocal() { + private final ThreadLocal mutationGuardState = new GuardState(); + private static class GuardState extends ThreadLocal { @Override protected Boolean initialValue() { return Boolean.TRUE; } - }; + } @Override public boolean isMutationAllowed() { diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/registry/RuleContext.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/registry/RuleContext.java index ada40864a8a1..2281dd8308cb 100644 --- a/subprojects/model-core/src/main/java/org/gradle/model/internal/registry/RuleContext.java +++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/registry/RuleContext.java @@ -24,12 +24,7 @@ public class RuleContext { - private static final ThreadLocal> STACK = new ThreadLocal>() { - @Override - protected Deque initialValue() { - return new ArrayDeque(); - } - }; + private static final ThreadLocal> STACK = ThreadLocal.withInitial(ArrayDeque::new); @Nullable public static ModelRuleDescriptor get() { From e2ba0efac7981eef03f87425b8a61cd3c8566f94 Mon Sep 17 00:00:00 2001 From: Louis Jacomet Date: Thu, 1 Dec 2022 15:55:13 +0100 Subject: [PATCH 03/17] Fix upgrade note following Groovy update The previous Groovy version was 3.0.10 and not 3.0.11. --- .../docs/src/docs/userguide/migration/upgrading_version_7.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subprojects/docs/src/docs/userguide/migration/upgrading_version_7.adoc b/subprojects/docs/src/docs/userguide/migration/upgrading_version_7.adoc index 2d90feea08ee..f277c06ff8db 100644 --- a/subprojects/docs/src/docs/userguide/migration/upgrading_version_7.adoc +++ b/subprojects/docs/src/docs/userguide/migration/upgrading_version_7.adoc @@ -106,7 +106,7 @@ tasks.withType().configureEach { Groovy has been updated to https://groovy-lang.org/changelogs/changelog-3.0.13.html[Groovy 3.0.13]. -Since the previous version was 3.0.11, the https://groovy-lang.org/changelogs/changelog-3.0.12.html[3.0.12 changes] are also included. +Since the previous version was 3.0.10, the https://groovy-lang.org/changelogs/changelog-3.0.11.html[3.0.11] and https://groovy-lang.org/changelogs/changelog-3.0.12.html[3.0.12] changes are also included. ==== Upgrade to PMD 6.48.0 From be776d67675620014c3486edaef637a453e8536e Mon Sep 17 00:00:00 2001 From: Louis Jacomet Date: Fri, 2 Dec 2022 12:21:24 +0100 Subject: [PATCH 04/17] Prepare for 7.6.1 release --- released-versions.json | 6 +- .../changes/accepted-public-api-changes.json | 67 +------------------ subprojects/docs/src/docs/release/notes.md | 9 +++ version.txt | 2 +- 4 files changed, 17 insertions(+), 67 deletions(-) diff --git a/released-versions.json b/released-versions.json index bfc25ec83871..7c1dedc798f9 100644 --- a/released-versions.json +++ b/released-versions.json @@ -8,6 +8,10 @@ "buildTime": "20220712114039+0000" }, "finalReleases": [ + { + "version": "7.6", + "buildTime": "20221125133510+0000" + }, { "version": "7.5.1", "buildTime": "20220805211756+0000" @@ -485,4 +489,4 @@ "buildTime": "20090720085013+0200" } ] -} +} \ No newline at end of file diff --git a/subprojects/architecture-test/src/changes/accepted-public-api-changes.json b/subprojects/architecture-test/src/changes/accepted-public-api-changes.json index b54ce8881f4e..4017e1002927 100644 --- a/subprojects/architecture-test/src/changes/accepted-public-api-changes.json +++ b/subprojects/architecture-test/src/changes/accepted-public-api-changes.json @@ -1,66 +1,3 @@ { - "acceptedApiChanges": [ - { - "type": "org.gradle.api.tasks.diagnostics.PropertyReportTask", - "member": "Method org.gradle.api.tasks.diagnostics.PropertyReportTask.generate(org.gradle.api.Project)", - "acceptation": "Make PropertyReportTask compatible with configuration caching", - "changes": [ - "Method has been removed" - ] - }, - { - "type": "org.gradle.api.tasks.diagnostics.ProjectReportTask", - "member": "Method org.gradle.api.tasks.diagnostics.ProjectReportTask.generate(org.gradle.api.Project)", - "acceptation": "Make ProjectReportTask compatible with configuration caching", - "changes": [ - "Method has been removed" - ] - }, - { - "type": "org.gradle.api.tasks.diagnostics.AbstractDependencyReportTask", - "member": "Method org.gradle.api.tasks.diagnostics.AbstractDependencyReportTask.generate(org.gradle.api.Project)", - "acceptation": "Make AbstractDependencyReportTask compatible with configuration caching", - "changes": [ - "Method has been removed" - ] - }, - { - "type": "org.gradle.api.attributes.AttributesSchema", - "member": "Method org.gradle.api.attributes.AttributesSchema.setAttributeDisambiguationPrecedence(java.util.List)", - "acceptation": "Changed argument type to List to better signify usage of the argument", - "changes": [ - "Method added to interface" - ] - }, - { - "type": "org.gradle.plugin.devel.PluginDeclaration", - "member": "Class org.gradle.plugin.devel.PluginDeclaration", - "acceptation": "Added a SetProperty to it and this change is needed for it to be automatically handled", - "changes": [ - "Class is now abstract" - ] - }, - { - "type": "org.gradle.kotlin.dsl.DependencyAdderExtensionsKt", - "member": "Method org.gradle.kotlin.dsl.DependencyAdderExtensionsKt.invoke(org.gradle.api.artifacts.dsl.DependencyAdder,org.gradle.api.artifacts.Dependency,org.gradle.api.Action)", - "acceptation": "@since was added, but the Kotlin ABI checker cannot match the method due to generics", - "changes": [ - "METHOD_ADDED_TO_PUBLIC_CLASS" - ] - }, - { - "type": "org.gradle.kotlin.dsl.DependencyAdderExtensionsKt", - "member": "Method org.gradle.kotlin.dsl.DependencyAdderExtensionsKt.module(org.gradle.api.artifacts.dsl.Dependencies,java.lang.String,java.lang.String,java.lang.String)", - "acceptation": "This makes it possible to call module(group, name, version) with named parameters", - "changes": [ - "METHOD_ADDED_TO_PUBLIC_CLASS" - ] - }, - { - "type": "org.gradle.kotlin.dsl.ToolchainManagementExtensionsKt", - "member": "Class org.gradle.kotlin.dsl.ToolchainManagementExtensionsKt", - "acceptation": "dynamically generated accessors don't work for settings, so need to add static ones, until that problem is fixed", - "changes": [] - } - ] -} + "acceptedApiChanges": [] +} \ No newline at end of file diff --git a/subprojects/docs/src/docs/release/notes.md b/subprojects/docs/src/docs/release/notes.md index 19c5b277c17c..18ee18cb09d1 100644 --- a/subprojects/docs/src/docs/release/notes.md +++ b/subprojects/docs/src/docs/release/notes.md @@ -1,6 +1,15 @@ The Gradle team is excited to announce Gradle @version@. +This is the first patch release for Gradle 7.6. + +It fixes the following issues: +* TODO + +We recommend users upgrade to @version@ instead of 7.6. + +--- + This release includes [building and running code with Java 19](#java19), a flag to [rerun tasks individually](#individual-rerun), a new [strongly-typed dependencies block](#strongly-typed-dependencies) for JVM test suites, diff --git a/version.txt b/version.txt index f5cce03c304f..e8be68404bcb 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -7.6 \ No newline at end of file +7.6.1 From 62370e79ef95c1f9bb898f6fc7beaf3d0dc8bc66 Mon Sep 17 00:00:00 2001 From: Bo Zhang Date: Mon, 5 Dec 2022 17:23:59 +0800 Subject: [PATCH 05/17] Remove cygwin gcc --- .../org/gradle/nativeplatform/fixtures/AvailableToolChains.java | 1 - 1 file changed, 1 deletion(-) diff --git a/subprojects/platform-native/src/testFixtures/groovy/org/gradle/nativeplatform/fixtures/AvailableToolChains.java b/subprojects/platform-native/src/testFixtures/groovy/org/gradle/nativeplatform/fixtures/AvailableToolChains.java index 677db2d857ba..f4e6a08eac09 100755 --- a/subprojects/platform-native/src/testFixtures/groovy/org/gradle/nativeplatform/fixtures/AvailableToolChains.java +++ b/subprojects/platform-native/src/testFixtures/groovy/org/gradle/nativeplatform/fixtures/AvailableToolChains.java @@ -118,7 +118,6 @@ public static List getToolChains() { if (OperatingSystem.current().isWindows()) { compilers.addAll(findVisualCpps()); compilers.add(findMinGW()); - compilers.add(findCygwin()); } else if (OperatingSystem.current().isMacOsX()) { compilers.addAll(findClangs(true)); compilers.addAll(findGccs(false)); From 0421be59b9bffd4a0247b56f1f3631d7889c3d11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B3zsef=20Bart=C3=B3k?= Date: Thu, 8 Dec 2022 15:19:54 +0200 Subject: [PATCH 06/17] Check Java Toolchain install folder for left-overs (backport #22819) --- .../inspection/JvmInstallationMetadata.java | 15 +++ ...oadSpiAuthenticationIntegrationTest.groovy | 6 +- .../internal/install/JdkCacheDirectory.java | 101 +++++++++++++++--- 3 files changed, 104 insertions(+), 18 deletions(-) diff --git a/subprojects/jvm-services/src/main/java/org/gradle/internal/jvm/inspection/JvmInstallationMetadata.java b/subprojects/jvm-services/src/main/java/org/gradle/internal/jvm/inspection/JvmInstallationMetadata.java index 2b566019e3fd..9cdb48b5abb8 100644 --- a/subprojects/jvm-services/src/main/java/org/gradle/internal/jvm/inspection/JvmInstallationMetadata.java +++ b/subprojects/jvm-services/src/main/java/org/gradle/internal/jvm/inspection/JvmInstallationMetadata.java @@ -261,6 +261,21 @@ public Throwable getErrorCause() { public boolean isValidInstallation() { return true; } + + @Override + public String toString() { + return "DefaultJvmInstallationMetadata{" + + "languageVersion=" + languageVersion + + ", javaVersion='" + javaVersion + '\'' + + ", javaVendor='" + javaVendor + '\'' + + ", runtimeName='" + runtimeName + '\'' + + ", runtimeVersion='" + runtimeVersion + '\'' + + ", jvmName='" + jvmName + '\'' + + ", jvmVersion='" + jvmVersion + '\'' + + ", jvmVendor='" + jvmVendor + '\'' + + ", architecture='" + architecture + '\'' + + '}'; + } } class FailureInstallationMetadata implements JvmInstallationMetadata { diff --git a/subprojects/platform-jvm/src/integTest/groovy/org/gradle/jvm/toolchain/JavaToolchainDownloadSpiAuthenticationIntegrationTest.groovy b/subprojects/platform-jvm/src/integTest/groovy/org/gradle/jvm/toolchain/JavaToolchainDownloadSpiAuthenticationIntegrationTest.groovy index 0f3138f25e3f..2703f451d231 100644 --- a/subprojects/platform-jvm/src/integTest/groovy/org/gradle/jvm/toolchain/JavaToolchainDownloadSpiAuthenticationIntegrationTest.groovy +++ b/subprojects/platform-jvm/src/integTest/groovy/org/gradle/jvm/toolchain/JavaToolchainDownloadSpiAuthenticationIntegrationTest.groovy @@ -82,7 +82,8 @@ class JavaToolchainDownloadSpiAuthenticationIntegrationTest extends AbstractJava .assertHasCause("Error while evaluating property 'javaCompiler' of task ':compileJava'.") .assertHasCause("Failed to calculate the value of task ':compileJava' property 'javaCompiler'.") .assertHasCause("Unable to download toolchain matching the requirements ({languageVersion=99, vendor=matching('exotic'), implementation=vendor-specific}) from '" + archiveUri + "'.") - .assertHasCause("Provisioned toolchain '" + temporaryFolder.testDirectory.file("user-home", "jdks", "toolchain") + "' could not be probed.") + .assertHasCause("Provisioned toolchain '" + temporaryFolder.testDirectory.file("user-home", "jdks", "toolchain") + "' could not be probed: " + + "A problem occurred starting process 'command '") } @ToBeFixedForConfigurationCache(because = "Fails the build with an additional error") @@ -135,7 +136,8 @@ class JavaToolchainDownloadSpiAuthenticationIntegrationTest extends AbstractJava .assertHasCause("Error while evaluating property 'javaCompiler' of task ':compileJava'") .assertHasCause("Failed to calculate the value of task ':compileJava' property 'javaCompiler'.") .assertHasCause("Unable to download toolchain matching the requirements ({languageVersion=99, vendor=matching('exotic'), implementation=vendor-specific}) from '" + archiveUri + "'.") - .assertHasCause("Provisioned toolchain '" + temporaryFolder.testDirectory.file("user-home", "jdks", "toolchain") + "' could not be probed.") + .assertHasCause("Provisioned toolchain '" + temporaryFolder.testDirectory.file("user-home", "jdks", "toolchain") + "' could not be probed: " + + "A problem occurred starting process 'command '") } private static String customToolchainResolverCode(String uri) { diff --git a/subprojects/platform-jvm/src/main/java/org/gradle/jvm/toolchain/internal/install/JdkCacheDirectory.java b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/toolchain/internal/install/JdkCacheDirectory.java index c585f8171293..9f6f2f8f9864 100644 --- a/subprojects/platform-jvm/src/main/java/org/gradle/jvm/toolchain/internal/install/JdkCacheDirectory.java +++ b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/toolchain/internal/install/JdkCacheDirectory.java @@ -118,32 +118,101 @@ private File getJavaHome(File markedLocation) { * Unpacks and installs the given JDK archive. Returns a file pointing to the java home directory. */ public File provisionFromArchive(JavaToolchainSpec spec, File jdkArchive, URI uri) { - final File unpackFolder = unpack(jdkArchive); - File markedLocation = markedLocation(unpackFolder); - markAsReady(markedLocation); + final File[] unpackFolder = new File[1]; + final File[] installFolder = new File[1]; + try { + unpackFolder[0] = unpack(jdkArchive); + + //put the marker file in the unpack folder from where it will get in its proper place + //when the contents are copied to the installation folder + File markedLocation = markLocationInsideFolder(unpackFolder[0]); + + //probe unpacked installation for its metadata + JvmInstallationMetadata metadata = getMetadata(markedLocation); + + validateMetadataMatchesSpec(spec, uri, metadata); + + String installFolderName = getInstallFolderName(metadata); + installFolder[0] = new File(jdkDirectory, installFolderName); + + //make sure the install folder is empty + checkInstallFolderForLeftoverContent(installFolder[0], uri, spec, metadata); + operations.delete(installFolder[0]); + + //copy content of unpack folder to install folder, including the marker file + operations.copy(copySpec -> { + copySpec.from(unpackFolder[0]); + copySpec.into(installFolder[0]); + }); + + LOGGER.info("Installed toolchain from {} into {}", uri, installFolder[0]); + return getJavaHome(markedLocation(installFolder[0])); + } catch (Throwable t) { + // provisioning failed, clean up leftovers + if (installFolder[0] != null) { + operations.delete(installFolder[0]); + } + throw t; + } finally { + // clean up temporary unpack folder, regardless if provisioning succeeded or not + if (unpackFolder[0] != null) { + operations.delete(unpackFolder[0]); + } + } + } + + private void checkInstallFolderForLeftoverContent(File installFolder, URI uri, JavaToolchainSpec spec, JvmInstallationMetadata metadata) { + if (!installFolder.exists()) { + return; //install folder doesn't even exist + } + + File[] filesInInstallFolder = installFolder.listFiles(); + if (filesInInstallFolder == null || filesInInstallFolder.length == 0) { + return; //no files in install folder + } + + File markerLocation = markedLocation(installFolder); + if (!isMarkedLocation(markerLocation)) { + return; //no marker found + } + + String leftoverMetadata; + try { + leftoverMetadata = getMetadata(markerLocation).toString(); + } catch (Exception e) { + LOGGER.debug("Failed determining metadata of installation leftover", e); + leftoverMetadata = "Could not be determined due to: " + e.getMessage(); + } + LOGGER.warn("While provisioning Java toolchain from '{}' to satisfy spec '{}' (with metadata '{}'), " + + "leftover content (with metadata '{}') was found in the install folder '{}'. " + + "The existing installation will be replaced by the new download.", + uri, spec, metadata, leftoverMetadata, installFolder); + } + + private JvmInstallationMetadata getMetadata(File markedLocation) { File javaHome = getJavaHome(markedLocation); JvmInstallationMetadata metadata = detector.getMetadata(new InstallationLocation(javaHome, "provisioned toolchain")); if (!metadata.isValidInstallation()) { - throw new GradleException("Provisioned toolchain '" + javaHome + "' could not be probed."); - } - if (!new JavaToolchainMatcher(spec).test(metadata)) { - throw new GradleException("Toolchain provisioned from '" + uri + "' doesn't satisfy the specification: " + spec.getDisplayName() + "."); + throw new GradleException("Provisioned toolchain '" + javaHome + "' could not be probed: " + metadata.getErrorMessage(), metadata.getErrorCause()); } - File installFolder = new File(jdkDirectory, toDirectoryName(metadata)); - operations.copy(copySpec -> { - copySpec.from(unpackFolder); - copySpec.into(installFolder); - }); - operations.delete(unpackFolder); + return metadata; + } - LOGGER.info("Installed toolchain from {} into {}", uri, installFolder); + private File markLocationInsideFolder(File unpackedInstallationFolder) { + File markedLocation = markedLocation(unpackedInstallationFolder); + markAsReady(markedLocation); + return markedLocation; + } - return getJavaHome(markedLocation(installFolder)); + private static void validateMetadataMatchesSpec(JavaToolchainSpec spec, URI uri, JvmInstallationMetadata metadata) { + if (!new JavaToolchainMatcher(spec).test(metadata)) { + throw new GradleException("Toolchain provisioned from '" + uri + "' doesn't satisfy the specification: " + spec.getDisplayName() + "."); + } } - private static String toDirectoryName(JvmInstallationMetadata metadata) { + private static String getInstallFolderName(JvmInstallationMetadata metadata) { String vendor = metadata.getJvmVendor(); if (vendor == null || vendor.isEmpty()) { vendor = metadata.getVendor().getRawVendor(); From 5c172933eed519b7173bd1a15d4e544ea093b675 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B3zsef=20Bart=C3=B3k?= Date: Fri, 9 Dec 2022 11:21:33 +0200 Subject: [PATCH 07/17] Fix the issue of provisioning the same toolchain multiple times (backport #23024) --- .../internal/JavaInstallationRegistry.java | 39 +++++++- .../internal/JavaToolchainQueryService.java | 37 +++++--- ...chainDownloadComplexProjectSoakTest.groovy | 90 +++++++++++++++++++ .../JavaToolchainDownloadSoakTest.groovy | 5 +- 4 files changed, 153 insertions(+), 18 deletions(-) create mode 100644 subprojects/soak/src/integTest/groovy/org/gradle/jvm/toolchain/JavaToolchainDownloadComplexProjectSoakTest.groovy diff --git a/subprojects/jvm-services/src/main/java/org/gradle/jvm/toolchain/internal/JavaInstallationRegistry.java b/subprojects/jvm-services/src/main/java/org/gradle/jvm/toolchain/internal/JavaInstallationRegistry.java index e4b9d4660b97..a541a2e1ea85 100644 --- a/subprojects/jvm-services/src/main/java/org/gradle/jvm/toolchain/internal/JavaInstallationRegistry.java +++ b/subprojects/jvm-services/src/main/java/org/gradle/jvm/toolchain/internal/JavaInstallationRegistry.java @@ -17,8 +17,6 @@ package org.gradle.jvm.toolchain.internal; import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Supplier; -import com.google.common.base.Suppliers; import org.gradle.api.GradleException; import org.gradle.api.logging.Logger; import org.gradle.api.logging.Logging; @@ -37,12 +35,13 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; import java.util.function.Predicate; +import java.util.function.Supplier; import java.util.stream.Collectors; public class JavaInstallationRegistry { private final BuildOperationExecutor executor; - private final Supplier> installations; + private final Installations installations; private final Logger logger; private final OperatingSystem os; @@ -54,7 +53,7 @@ public JavaInstallationRegistry(List suppliers, BuildOpera private JavaInstallationRegistry(List suppliers, Logger logger, BuildOperationExecutor executor, OperatingSystem os) { this.logger = logger; this.executor = executor; - this.installations = Suppliers.memoize(() -> collectInBuildOperation(suppliers)); + this.installations = new Installations(() -> collectInBuildOperation(suppliers)); this.os = os; } @@ -71,6 +70,10 @@ public Set listInstallations() { return installations.get(); } + public void addInstallation(InstallationLocation installation) { + installations.add(installation); + } + private Set collectInstallations(List suppliers) { return suppliers.parallelStream() .map(InstallationSupplier::get) @@ -146,4 +149,32 @@ public BuildOperationDescriptor.Builder description() { } } + private static class Installations { + + private final Supplier> initializer; + + private Set locations = null; + + Installations(Supplier> initializer) { + this.initializer = initializer; + } + + synchronized Set get() { + initIfNeeded(); + return locations; + } + + synchronized void add(InstallationLocation location) { + initIfNeeded(); + locations.add(location); + } + + private void initIfNeeded() { + if (locations == null) { + locations = initializer.get(); + } + } + + } + } diff --git a/subprojects/platform-jvm/src/main/java/org/gradle/jvm/toolchain/internal/JavaToolchainQueryService.java b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/toolchain/internal/JavaToolchainQueryService.java index f5ec0db7bcb0..3e26e40c8e76 100644 --- a/subprojects/platform-jvm/src/main/java/org/gradle/jvm/toolchain/internal/JavaToolchainQueryService.java +++ b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/toolchain/internal/JavaToolchainQueryService.java @@ -25,6 +25,8 @@ import org.gradle.api.provider.ProviderFactory; import org.gradle.internal.deprecation.DeprecationLogger; import org.gradle.internal.jvm.Jvm; +import org.gradle.internal.service.scopes.Scopes; +import org.gradle.internal.service.scopes.ServiceScope; import org.gradle.jvm.toolchain.JavaToolchainSpec; import org.gradle.jvm.toolchain.internal.install.DefaultJavaToolchainProvisioningService; import org.gradle.jvm.toolchain.internal.install.JavaToolchainProvisioningService; @@ -36,6 +38,7 @@ import java.util.Objects; import java.util.Optional; +@ServiceScope(Scopes.Project.class) public class JavaToolchainQueryService { private final JavaInstallationRegistry registry; @@ -121,30 +124,42 @@ private JavaToolchain query(JavaToolchainSpec spec) { if (spec instanceof CurrentJvmToolchainSpec) { return asToolchain(new InstallationLocation(Jvm.current().getJavaHome(), "current JVM"), spec).get(); } + if (spec instanceof SpecificInstallationToolchainSpec) { return asToolchain(new InstallationLocation(((SpecificInstallationToolchainSpec) spec).getJavaHome(), "specific installation"), spec).get(); } - return registry.listInstallations().stream() - .map(javaHome -> asToolchain(javaHome, spec)) - .filter(Optional::isPresent) - .map(Optional::get) - .filter(new JavaToolchainMatcher(spec)) - .min(new JavaToolchainComparator()) - .orElseGet(() -> downloadToolchain(spec)); + Optional detectedToolchain = registry.listInstallations().stream() + .map(javaHome -> asToolchain(javaHome, spec)) + .filter(Optional::isPresent) + .map(Optional::get) + .filter(new JavaToolchainMatcher(spec)) + .min(new JavaToolchainComparator()); + + if (detectedToolchain.isPresent()) { + return detectedToolchain.get(); + } + + InstallationLocation downloadedInstallation = downloadToolchain(spec); + JavaToolchain downloadedToolchain = asToolchainOrThrow(downloadedInstallation, spec); + registry.addInstallation(downloadedInstallation); + return downloadedToolchain; } - private JavaToolchain downloadToolchain(JavaToolchainSpec spec) { + private InstallationLocation downloadToolchain(JavaToolchainSpec spec) { final Optional installation = installService.tryInstall(spec); if (!installation.isPresent()) { throw new NoToolchainAvailableException(spec, detectEnabled.getOrElse(true), downloadEnabled.getOrElse(true)); } - Optional toolchain = asToolchain(new InstallationLocation(installation.get(), "provisioned toolchain"), spec); + return new InstallationLocation(installation.get(), "provisioned toolchain"); + } + + private JavaToolchain asToolchainOrThrow(InstallationLocation javaHome, JavaToolchainSpec spec) { + Optional toolchain = asToolchain(javaHome, spec); if (!toolchain.isPresent()) { - throw new GradleException("Provisioned toolchain '" + installation.get() + "' could not be probed."); + throw new GradleException("Toolchain installation '" + javaHome.getLocation() + "' could not be probed."); } - return toolchain.get(); } diff --git a/subprojects/soak/src/integTest/groovy/org/gradle/jvm/toolchain/JavaToolchainDownloadComplexProjectSoakTest.groovy b/subprojects/soak/src/integTest/groovy/org/gradle/jvm/toolchain/JavaToolchainDownloadComplexProjectSoakTest.groovy new file mode 100644 index 000000000000..6b238975f95d --- /dev/null +++ b/subprojects/soak/src/integTest/groovy/org/gradle/jvm/toolchain/JavaToolchainDownloadComplexProjectSoakTest.groovy @@ -0,0 +1,90 @@ +/* + * Copyright 2022 the original author or authors. + * + * 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 org.gradle.jvm.toolchain + +import org.gradle.integtests.fixtures.AbstractIntegrationSpec + +class JavaToolchainDownloadComplexProjectSoakTest extends AbstractIntegrationSpec { + + def setup() { + executer.requireOwnGradleUserHomeDir() + executer.withToolchainDownloadEnabled() + } + + def "multiple subprojects with identical toolchain definitions"() { + given: + settingsFile << settingsForBuildWithSubprojects() + + setupSubproject("subproject1", "Foo", "ADOPTIUM") + setupSubproject("subproject2", "Bar", "ADOPTIUM") + + when: + result = executer + .withTasks("compileJava") + .run() + + then: + !result.plainTextOutput.matches("(?s).*The existing installation will be replaced by the new download.*") + } + + def "multiple subprojects with different toolchain definitions"() { + given: + settingsFile << settingsForBuildWithSubprojects() + + setupSubproject("subproject1", "Foo", "ADOPTIUM") + setupSubproject("subproject2", "Bar", "ORACLE") + + when: + result = executer + .withTasks("compileJava") + .withArgument("--info") + .run() + + then: + result.plainTextOutput.matches("(?s).*Compiling with toolchain.*adoptium.*") + result.plainTextOutput.matches("(?s).*Compiling with toolchain.*oracle.*") + } + + private String settingsForBuildWithSubprojects() { + return """ + plugins { + id 'org.gradle.toolchains.foojay-resolver-convention' version '0.2' + } + rootProject.name = 'main' + + include('subproject1') + include('subproject2') + """ + } + + private void setupSubproject(String subprojectName, String className, String vendorName) { + file("${subprojectName}/build.gradle") << """ + plugins { + id 'java' + } + + java { + toolchain { + languageVersion = JavaLanguageVersion.of(11) + vendor = JvmVendorSpec.${vendorName} + } + } + """ + file("${subprojectName}/src/main/java/${className}.java") << "public class ${className} {}" + } + +} diff --git a/subprojects/soak/src/integTest/groovy/org/gradle/jvm/toolchain/JavaToolchainDownloadSoakTest.groovy b/subprojects/soak/src/integTest/groovy/org/gradle/jvm/toolchain/JavaToolchainDownloadSoakTest.groovy index 444468b5b1a2..c8bc3cf7c82b 100644 --- a/subprojects/soak/src/integTest/groovy/org/gradle/jvm/toolchain/JavaToolchainDownloadSoakTest.groovy +++ b/subprojects/soak/src/integTest/groovy/org/gradle/jvm/toolchain/JavaToolchainDownloadSoakTest.groovy @@ -37,14 +37,13 @@ class JavaToolchainDownloadSoakTest extends AbstractIntegrationSpec { executer.requireOwnGradleUserHomeDir() executer - .withToolchainDetectionEnabled() .withToolchainDownloadEnabled() } def "can download missing jdk automatically"() { when: result = executer - .withTasks("compileJava", "-Porg.gradle.java.installations.auto-detect=false") + .withTasks("compileJava") .expectDocumentedDeprecationWarning("Java toolchain auto-provisioning needed, but no java toolchain repositories declared by the build. Will rely on the built-in repository. " + "This behaviour has been deprecated and is scheduled to be removed in Gradle 8.0. " + "In order to declare a repository for java toolchains, you must edit your settings script and add one via the toolchainManagement block. " + @@ -67,7 +66,7 @@ class JavaToolchainDownloadSoakTest extends AbstractIntegrationSpec { when: result = executer - .withTasks("compileJava", "-Porg.gradle.java.installations.auto-detect=false") + .withTasks("compileJava") .expectDocumentedDeprecationWarning("Java toolchain auto-provisioning needed, but no java toolchain repositories declared by the build. Will rely on the built-in repository. " + "This behaviour has been deprecated and is scheduled to be removed in Gradle 8.0. " + "In order to declare a repository for java toolchains, you must edit your settings script and add one via the toolchainManagement block. " + From 0a7f47835126e00e7634ffda67d2727f2173e092 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B3zsef=20Bart=C3=B3k?= Date: Sat, 10 Dec 2022 14:08:18 +0200 Subject: [PATCH 08/17] Consider IBM and IBM_SEMERU vendors identical, deprecate the later --- .../src/docs/userguide/jvm/toolchains.adoc | 1 - .../migration/upgrading_version_7.adoc | 2 +- .../toolchain-filters/groovy/build.gradle | 2 +- .../toolchain-filters/kotlin/build.gradle.kts | 2 +- .../internal/jvm/inspection/JvmVendor.java | 3 +- .../DefaultJvmMetadataDetectorTest.groovy | 48 ++++-- ...avaToolchainDownloadIntegrationTest.groovy | 6 +- .../gradle/jvm/toolchain/JvmVendorSpec.java | 5 +- .../internal/JavaToolchainMatcher.java | 9 +- .../install/AdoptOpenJdkRemoteBinary.java | 4 +- .../AdoptOpenJdkRemoteBinaryTest.groovy | 4 +- .../internal/JavaToolchainMatcherTest.groovy | 162 ++++++++++++++++++ .../JavaToolchainQueryServiceTest.groovy | 6 +- 13 files changed, 218 insertions(+), 36 deletions(-) create mode 100644 subprojects/platform-jvm/src/test/groovy/org/gradle/jvm/toolchain/internal/JavaToolchainMatcherTest.groovy diff --git a/subprojects/docs/src/docs/userguide/jvm/toolchains.adoc b/subprojects/docs/src/docs/userguide/jvm/toolchains.adoc index 9d207d77ee86..d3bd070fbb2a 100644 --- a/subprojects/docs/src/docs/userguide/jvm/toolchains.adoc +++ b/subprojects/docs/src/docs/userguide/jvm/toolchains.adoc @@ -387,7 +387,6 @@ Sorting is done based on the following rules: .. GRAAL_VM .. HEWLETT_PACKARD .. IBM -.. IBM_SEMERU .. MICROSOFT .. ORACLE .. SAP diff --git a/subprojects/docs/src/docs/userguide/migration/upgrading_version_7.adoc b/subprojects/docs/src/docs/userguide/migration/upgrading_version_7.adoc index 2d90feea08ee..f3c6f02ecd95 100644 --- a/subprojects/docs/src/docs/userguide/migration/upgrading_version_7.adoc +++ b/subprojects/docs/src/docs/userguide/migration/upgrading_version_7.adoc @@ -538,7 +538,7 @@ Following the move from AdoptOpenJDK to Adoptium, under the Eclipse foundation, Instead, an Eclipse Temurin or IBM Semeru build is returned. Gradle 7.4+ will now emit a deprecation warning when the AdoptOpenJDK vendor is specified in the <> and it is used by auto provisioning. -If you must use AdoptOpenJDK, you should turn off auto-download. If an Eclipse Temurin or IBM Semeru build works for you, specify `JvmVendorSpec.ADOPTIUM` or `JvmVendorSpec.IBM_SEMERU` as the vendor or leave the vendor unspecified. +If you must use AdoptOpenJDK, you should turn off auto-download. If an Eclipse Temurin or IBM Semeru build works for you, specify `JvmVendorSpec.ADOPTIUM` or `JvmVendorSpec.IBM` as the vendor or leave the vendor unspecified. [[empty_directories_file_tree]] ==== File trees and empty directory handling diff --git a/subprojects/docs/src/snippets/java/toolchain-filters/groovy/build.gradle b/subprojects/docs/src/snippets/java/toolchain-filters/groovy/build.gradle index 8a431fa2eda2..39a69909f09c 100644 --- a/subprojects/docs/src/snippets/java/toolchain-filters/groovy/build.gradle +++ b/subprojects/docs/src/snippets/java/toolchain-filters/groovy/build.gradle @@ -25,7 +25,7 @@ java { java { toolchain { languageVersion = JavaLanguageVersion.of(11) - vendor = JvmVendorSpec.IBM_SEMERU + vendor = JvmVendorSpec.IBM implementation = JvmImplementation.J9 } } diff --git a/subprojects/docs/src/snippets/java/toolchain-filters/kotlin/build.gradle.kts b/subprojects/docs/src/snippets/java/toolchain-filters/kotlin/build.gradle.kts index b6b13a6edaa7..a91542f7450c 100644 --- a/subprojects/docs/src/snippets/java/toolchain-filters/kotlin/build.gradle.kts +++ b/subprojects/docs/src/snippets/java/toolchain-filters/kotlin/build.gradle.kts @@ -26,7 +26,7 @@ java { java { toolchain { languageVersion.set(JavaLanguageVersion.of(11)) - vendor.set(JvmVendorSpec.IBM_SEMERU) + vendor.set(JvmVendorSpec.IBM) implementation.set(JvmImplementation.J9) } } diff --git a/subprojects/jvm-services/src/main/java/org/gradle/internal/jvm/inspection/JvmVendor.java b/subprojects/jvm-services/src/main/java/org/gradle/internal/jvm/inspection/JvmVendor.java index 0e053e322649..31f8edd5a943 100644 --- a/subprojects/jvm-services/src/main/java/org/gradle/internal/jvm/inspection/JvmVendor.java +++ b/subprojects/jvm-services/src/main/java/org/gradle/internal/jvm/inspection/JvmVendor.java @@ -29,8 +29,7 @@ enum KnownJvmVendor { BELLSOFT("bellsoft", "BellSoft Liberica"), GRAAL_VM("graalvm community", "GraalVM Community"), HEWLETT_PACKARD("hewlett-packard", "HP-UX"), - IBM("ibm", "IBM"), - IBM_SEMERU("international business machines corporation", "IBM Semeru Runtimes"), + IBM("ibm", "ibm|international business machines corporation", "IBM"), MICROSOFT("microsoft", "Microsoft"), ORACLE("oracle", "Oracle"), SAP("sap se", "SAP SapMachine"), diff --git a/subprojects/jvm-services/src/test/groovy/org/gradle/internal/jvm/inspection/DefaultJvmMetadataDetectorTest.groovy b/subprojects/jvm-services/src/test/groovy/org/gradle/internal/jvm/inspection/DefaultJvmMetadataDetectorTest.groovy index df1a15e4f4e6..66aac24d49c0 100644 --- a/subprojects/jvm-services/src/test/groovy/org/gradle/internal/jvm/inspection/DefaultJvmMetadataDetectorTest.groovy +++ b/subprojects/jvm-services/src/test/groovy/org/gradle/internal/jvm/inspection/DefaultJvmMetadataDetectorTest.groovy @@ -120,12 +120,9 @@ class DefaultJvmMetadataDetectorTest extends Specification { 'temurinjdk17' | temurinJvm('17') | JavaVersion.VERSION_17 | 'Eclipse Temurin JDK 17' | false 'temurinjre8' | temurin8Jvm('8') | JavaVersion.VERSION_1_8 | 'Eclipse Temurin JRE 8' | true 'temurinjre11' | temurin11Jvm('11') | JavaVersion.VERSION_11 | 'Eclipse Temurin JRE 11' | true - 'semerujdk8' | semeruJvm('8') | JavaVersion.VERSION_1_8 | 'IBM Semeru Runtimes JDK 8' | false - 'semerujdk11' | semeruJvm('11') | JavaVersion.VERSION_11 | 'IBM Semeru Runtimes JDK 11' | false - 'semerujdk16' | semeruJvm('16') | JavaVersion.VERSION_16 | 'IBM Semeru Runtimes JDK 16' | false - 'semerujre8' | semeruJvm('8') | JavaVersion.VERSION_1_8 | 'IBM Semeru Runtimes JRE 8' | true - 'semerujre11' | semeruJvm('11') | JavaVersion.VERSION_11 | 'IBM Semeru Runtimes JRE 11' | true - 'semerujre16' | semeruJvm('16') | JavaVersion.VERSION_16 | 'IBM Semeru Runtimes JRE 16' | true + 'semerujdk11' | semeruJvm11() | JavaVersion.VERSION_11 | 'IBM JDK 11' | false + 'semerujdk16' | semeruJvm16() | JavaVersion.VERSION_16 | 'IBM JDK 16' | false + 'semerujdk17' | semeruJvm17() | JavaVersion.VERSION_17 | 'IBM JDK 17' | false 'whitespaces' | whitespaces('11.0.3') | JavaVersion.VERSION_11 | 'AdoptOpenJDK JRE 11' | true } @@ -154,9 +151,8 @@ class DefaultJvmMetadataDetectorTest extends Specification { 'ibmJdk7' | ibmJvm('7') | true 'ibmJdk8' | ibmJvm('8') | true 'ibmJdk9' | ibmJvm('9') | true - 'semeru8' | semeruJvm('8') | true - 'semeru11' | semeruJvm('11') | true - 'semeru16' | semeruJvm('16') | true + 'semeru11' | semeruJvm11() | true + 'semeru16' | semeruJvm16() | true 'temurin8' | temurin8Jvm('8') | false 'temurin11' | temurin11Jvm('11') | false 'temurin17' | temurinJvm('17') | false @@ -436,16 +432,42 @@ class DefaultJvmMetadataDetectorTest extends Specification { ] } - private static Map semeruJvm(String version) { + private static Map semeruJvm11() { ['java.home': "java-home", - 'java.version': "${version}", + 'java.version': "11.0.17", + 'java.vendor': "IBM Corporation", + 'os.arch': "x86_64", + 'java.vm.name': "Eclipse OpenJ9 VM", + 'java.vm.version': "openj9-0.35.0", + 'java.vm.vendor': "Eclipse OpenJ9", + 'java.runtime.name': "IBM Semeru Runtime Open Edition", + 'java.runtime.version': "11.0.17+8" + ] + } + + private static Map semeruJvm16() { + ['java.home': "java-home", + 'java.version': "16.0.2", 'java.vendor': "International Business Machines Corporation", 'os.arch': "x86_64", 'java.vm.name': "Eclipse OpenJ9 VM", 'java.vm.version': "openj9-0.27.0", - 'java.vm.vendor': "International Business Machines Corporation", + 'java.vm.vendor': "Eclipse OpenJ9", 'java.runtime.name': "IBM Semeru Runtime Open Edition", - 'java.runtime.version': "${version}-b08" + 'java.runtime.version': "16.0.2+7" + ] + } + + private static Map semeruJvm17() { + ['java.home': "java-home", + 'java.version': "17.0.5", + 'java.vendor': "IBM Corporation", + 'os.arch': "x86_64", + 'java.vm.name': "Eclipse OpenJ9 VM", + 'java.vm.version': "openj9-0.35.0", + 'java.vm.vendor': "Eclipse OpenJ9", + 'java.runtime.name': "IBM Semeru Runtime Open Edition", + 'java.runtime.version': "17.0.5+8" ] } diff --git a/subprojects/platform-jvm/src/integTest/groovy/org/gradle/jvm/toolchain/JavaToolchainDownloadIntegrationTest.groovy b/subprojects/platform-jvm/src/integTest/groovy/org/gradle/jvm/toolchain/JavaToolchainDownloadIntegrationTest.groovy index c8733dcd2e9d..dc8ac783a409 100644 --- a/subprojects/platform-jvm/src/integTest/groovy/org/gradle/jvm/toolchain/JavaToolchainDownloadIntegrationTest.groovy +++ b/subprojects/platform-jvm/src/integTest/groovy/org/gradle/jvm/toolchain/JavaToolchainDownloadIntegrationTest.groovy @@ -241,14 +241,14 @@ class JavaToolchainDownloadIntegrationTest extends AbstractIntegrationSpec { } @ToBeFixedForConfigurationCache(because = "Fails the build with an additional error") - def 'toolchain download of Semeru forces openj9'() { + def 'toolchain download of IBM forces openj9'() { buildFile << """ apply plugin: "java" java { toolchain { languageVersion = JavaLanguageVersion.of(99) - vendor = JvmVendorSpec.IBM_SEMERU + vendor = JvmVendorSpec.IBM } } """ @@ -274,7 +274,7 @@ class JavaToolchainDownloadIntegrationTest extends AbstractIntegrationSpec { then: failure.assertHasDescription("Execution failed for task ':compileJava'.") .assertHasCause("Failed to calculate the value of task ':compileJava' property 'javaCompiler'") - .assertHasCause("Unable to download toolchain matching the requirements ({languageVersion=99, vendor=IBM_SEMERU, implementation=vendor-specific}) from 'https://example.com/v3/binary/latest/99/ga/${os()}/${architecture()}/jdk/openj9/normal/adoptopenjdk'.") + .assertHasCause("Unable to download toolchain matching the requirements ({languageVersion=99, vendor=IBM, implementation=vendor-specific}) from 'https://example.com/v3/binary/latest/99/ga/${os()}/${architecture()}/jdk/openj9/normal/adoptopenjdk'.") .assertHasCause("Could not read 'https://example.com/v3/binary/latest/99/ga/${os()}/${architecture()}/jdk/openj9/normal/adoptopenjdk' as it does not exist.") } diff --git a/subprojects/platform-jvm/src/main/java/org/gradle/jvm/toolchain/JvmVendorSpec.java b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/toolchain/JvmVendorSpec.java index 8d5d9b4afb97..84d0ce811f16 100644 --- a/subprojects/platform-jvm/src/main/java/org/gradle/jvm/toolchain/JvmVendorSpec.java +++ b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/toolchain/JvmVendorSpec.java @@ -54,9 +54,10 @@ public abstract class JvmVendorSpec { * A constant for using IBM Semeru Runtimes as the JVM vendor. * * @since 7.4 + * @deprecated All IBM runtimes are Semeru runtimes, so no point in having two separate vendor definitions. IBM should be used instead. */ - @Incubating - public static final JvmVendorSpec IBM_SEMERU = matching(KnownJvmVendor.IBM_SEMERU); + @Deprecated + public static final JvmVendorSpec IBM_SEMERU = IBM; /** * A constant for using Microsoft OpenJDK as the JVM vendor. diff --git a/subprojects/platform-jvm/src/main/java/org/gradle/jvm/toolchain/internal/JavaToolchainMatcher.java b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/toolchain/internal/JavaToolchainMatcher.java index f6c1f9e82066..1a99ca10e62a 100644 --- a/subprojects/platform-jvm/src/main/java/org/gradle/jvm/toolchain/internal/JavaToolchainMatcher.java +++ b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/toolchain/internal/JavaToolchainMatcher.java @@ -21,7 +21,6 @@ import org.gradle.jvm.toolchain.JavaLanguageVersion; import org.gradle.jvm.toolchain.JavaToolchainSpec; import org.gradle.jvm.toolchain.JvmImplementation; -import org.gradle.jvm.toolchain.JvmVendorSpec; import java.util.function.Predicate; @@ -69,12 +68,12 @@ private static boolean isJ9ExplicitlyRequested(JavaToolchainSpec spec) { private static boolean isJ9RequestedViaVendor(JavaToolchainSpec spec) { DefaultJvmVendorSpec vendorSpec = (DefaultJvmVendorSpec) spec.getVendor().get(); - return vendorSpec != DefaultJvmVendorSpec.any() && vendorSpec.test(JvmVendor.KnownJvmVendor.IBM_SEMERU.asJvmVendor()); + return vendorSpec != DefaultJvmVendorSpec.any() && vendorSpec.test(JvmVendor.KnownJvmVendor.IBM.asJvmVendor()); } @SuppressWarnings("unchecked") - private Predicate vendorPredicate() { - JvmVendorSpec vendorSpec = spec.getVendor().get(); - return (Predicate) vendorSpec; + private Predicate vendorPredicate() { + return (DefaultJvmVendorSpec) spec.getVendor().get(); } + } diff --git a/subprojects/platform-jvm/src/main/java/org/gradle/jvm/toolchain/internal/install/AdoptOpenJdkRemoteBinary.java b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/toolchain/internal/install/AdoptOpenJdkRemoteBinary.java index 872f86e49769..bffaaec42ae7 100644 --- a/subprojects/platform-jvm/src/main/java/org/gradle/jvm/toolchain/internal/install/AdoptOpenJdkRemoteBinary.java +++ b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/toolchain/internal/install/AdoptOpenJdkRemoteBinary.java @@ -77,7 +77,7 @@ private boolean matchesVendor(JavaToolchainSpec spec) { return true; } - return vendorSpec.test(JvmVendor.KnownJvmVendor.IBM_SEMERU.asJvmVendor()); + return vendorSpec.test(JvmVendor.KnownJvmVendor.IBM.asJvmVendor()); } private URI constructUri(JavaToolchainSpec spec, BuildPlatform platform) { @@ -171,7 +171,7 @@ private static boolean isJ9ExplicitlyRequested(JavaToolchainSpec spec) { private static boolean isJ9RequestedViaVendor(JavaToolchainSpec spec) { DefaultJvmVendorSpec vendorSpec = (DefaultJvmVendorSpec) spec.getVendor().get(); - return vendorSpec != DefaultJvmVendorSpec.any() && vendorSpec.test(JvmVendor.KnownJvmVendor.IBM_SEMERU.asJvmVendor()); + return vendorSpec != DefaultJvmVendorSpec.any() && vendorSpec.test(JvmVendor.KnownJvmVendor.IBM.asJvmVendor()); } } diff --git a/subprojects/platform-jvm/src/test/groovy/org/gradle/jvm/toolchain/install/internal/AdoptOpenJdkRemoteBinaryTest.groovy b/subprojects/platform-jvm/src/test/groovy/org/gradle/jvm/toolchain/install/internal/AdoptOpenJdkRemoteBinaryTest.groovy index e836dade7dec..09cbfcaa8c85 100644 --- a/subprojects/platform-jvm/src/test/groovy/org/gradle/jvm/toolchain/install/internal/AdoptOpenJdkRemoteBinaryTest.groovy +++ b/subprojects/platform-jvm/src/test/groovy/org/gradle/jvm/toolchain/install/internal/AdoptOpenJdkRemoteBinaryTest.groovy @@ -116,7 +116,7 @@ class AdoptOpenJdkRemoteBinaryTest extends Specification { !download.isPresent() where: - vendor << [JvmVendorSpec.AMAZON, JvmVendorSpec.IBM] + vendor << [JvmVendorSpec.AMAZON] } def "can provide matching vendor spec using #vendor"() { @@ -136,7 +136,7 @@ class AdoptOpenJdkRemoteBinaryTest extends Specification { download.get().getUri() == URI.create("https://api.adoptopenjdk.net/v3/binary/latest/12/ga/mac/x64/jdk/hotspot/normal/adoptopenjdk") where: - vendor << [JvmVendorSpec.ADOPTOPENJDK, JvmVendorSpec.matching("adoptopenjdk"), DefaultJvmVendorSpec.any()] + vendor << [JvmVendorSpec.ADOPTOPENJDK, JvmVendorSpec.IBM, JvmVendorSpec.matching("adoptopenjdk"), DefaultJvmVendorSpec.any()] } def "can provide j9 impl if requested"() { diff --git a/subprojects/platform-jvm/src/test/groovy/org/gradle/jvm/toolchain/internal/JavaToolchainMatcherTest.groovy b/subprojects/platform-jvm/src/test/groovy/org/gradle/jvm/toolchain/internal/JavaToolchainMatcherTest.groovy new file mode 100644 index 000000000000..a5a896d3f6ed --- /dev/null +++ b/subprojects/platform-jvm/src/test/groovy/org/gradle/jvm/toolchain/internal/JavaToolchainMatcherTest.groovy @@ -0,0 +1,162 @@ +/* + * Copyright 2022 the original author or authors. + * + * 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 org.gradle.jvm.toolchain.internal + +import org.gradle.api.JavaVersion +import org.gradle.api.internal.file.TestFiles +import org.gradle.internal.jvm.inspection.DefaultJvmMetadataDetector +import org.gradle.internal.jvm.inspection.MetadataProbe +import org.gradle.internal.jvm.inspection.ProbedSystemProperty +import org.gradle.jvm.toolchain.JavaLanguageVersion +import org.gradle.jvm.toolchain.JvmImplementation +import org.gradle.jvm.toolchain.JvmVendorSpec +import org.gradle.process.ExecResult +import org.gradle.process.internal.ExecHandle +import org.gradle.process.internal.ExecHandleBuilder +import org.gradle.process.internal.ExecHandleFactory +import org.gradle.test.fixtures.file.TestFile +import org.gradle.util.TestUtil +import spock.lang.Specification +import spock.lang.TempDir + +class JavaToolchainMatcherTest extends Specification { + + @TempDir + File temporaryFolder + + TestFile tmpDir + def setup() { + tmpDir = new TestFile(new File(temporaryFolder, "tmp").tap { mkdirs() }) + } + + def "ibm vendors match semeru runtime metadata (java version: #javaVersion, vendor: #vendor, implementation: #implementation)"() { + given: + def execHandleFactory = createExecHandleFactory(systemProperties) + def detector = createDefaultJvmMetadataDetector(execHandleFactory) + def javaHome = new File(temporaryFolder, jdk).tap { mkdirs() } + def metadata = detector.getMetadata(testLocation(javaHome)) + + when: + def spec = new DefaultToolchainSpec(TestUtil.objectFactory()) + spec.getLanguageVersion().set(JavaLanguageVersion.of(javaVersion.getMajorVersion())) + spec.getVendor().set(vendor) + spec.getImplementation().set(implementation) + + then: + new JavaToolchainMatcher(spec).test(metadata) + + where: + jdk | systemProperties | javaVersion | vendor | implementation + 'semeru11' | semeruJvm11() | JavaVersion.VERSION_11 | JvmVendorSpec.IBM | JvmImplementation.VENDOR_SPECIFIC + 'semeru16' | semeruJvm16() | JavaVersion.VERSION_16 | JvmVendorSpec.IBM | JvmImplementation.VENDOR_SPECIFIC + 'semeru17' | semeruJvm17() | JavaVersion.VERSION_17 | JvmVendorSpec.IBM | JvmImplementation.VENDOR_SPECIFIC + + 'semeru11' | semeruJvm11() | JavaVersion.VERSION_11 | JvmVendorSpec.IBM | JvmImplementation.J9 + 'semeru16' | semeruJvm16() | JavaVersion.VERSION_16 | JvmVendorSpec.IBM | JvmImplementation.J9 + 'semeru17' | semeruJvm17() | JavaVersion.VERSION_17 | JvmVendorSpec.IBM | JvmImplementation.J9 + + 'semeru11' | semeruJvm11() | JavaVersion.VERSION_11 | JvmVendorSpec.IBM_SEMERU | JvmImplementation.VENDOR_SPECIFIC + 'semeru16' | semeruJvm16() | JavaVersion.VERSION_16 | JvmVendorSpec.IBM_SEMERU | JvmImplementation.VENDOR_SPECIFIC + 'semeru17' | semeruJvm17() | JavaVersion.VERSION_17 | JvmVendorSpec.IBM_SEMERU | JvmImplementation.VENDOR_SPECIFIC + + 'semeru11' | semeruJvm11() | JavaVersion.VERSION_11 | JvmVendorSpec.IBM_SEMERU | JvmImplementation.J9 + 'semeru16' | semeruJvm16() | JavaVersion.VERSION_16 | JvmVendorSpec.IBM_SEMERU | JvmImplementation.J9 + 'semeru17' | semeruJvm17() | JavaVersion.VERSION_17 | JvmVendorSpec.IBM_SEMERU | JvmImplementation.J9 + } + + def createExecHandleFactory(Map actualProperties) { + def probedSystemProperties = ProbedSystemProperty.values().findAll { it != ProbedSystemProperty.Z_ERROR } + if (!actualProperties.isEmpty()) { + assert actualProperties.keySet() == probedSystemProperties.collect { it.systemPropertyKey }.toSet() + } + + def execHandleFactory = Mock(ExecHandleFactory) + def exec = Mock(ExecHandleBuilder) + execHandleFactory.newExec() >> exec + PrintStream output + exec.setStandardOutput(_ as OutputStream) >> { OutputStream outputStream -> + output = new PrintStream(outputStream) + null + } + def handle = Mock(ExecHandle) + handle.start() >> handle + handle.waitForFinish() >> { + // important to output in the order of the enum members as parsing uses enum ordinals + probedSystemProperties.each { + def actualValue = actualProperties[it.systemPropertyKey] + // write conditionally to simulate wrong number of outputs + if (actualValue != null) { + output.println(MetadataProbe.MARKER_PREFIX + actualValue) + } + } + Mock(ExecResult) + } + exec.build() >> handle + execHandleFactory + } + + private DefaultJvmMetadataDetector createDefaultJvmMetadataDetector(ExecHandleFactory execHandleFactory) { + return new DefaultJvmMetadataDetector( + execHandleFactory, + TestFiles.tmpDirTemporaryFileProvider(tmpDir) + ) + } + + private InstallationLocation testLocation(File javaHome) { + new InstallationLocation(javaHome, "test") + } + + private static Map semeruJvm11() { + ['java.home': "java-home", + 'java.version': "11.0.17", + 'java.vendor': "IBM Corporation", + 'os.arch': "x86_64", + 'java.vm.name': "Eclipse OpenJ9 VM", + 'java.vm.version': "openj9-0.35.0", + 'java.vm.vendor': "Eclipse OpenJ9", + 'java.runtime.name': "IBM Semeru Runtime Open Edition", + 'java.runtime.version': "11.0.17+8" + ] + } + + private static Map semeruJvm16() { + ['java.home': "java-home", + 'java.version': "16.0.2", + 'java.vendor': "International Business Machines Corporation", + 'os.arch': "x86_64", + 'java.vm.name': "Eclipse OpenJ9 VM", + 'java.vm.version': "openj9-0.27.0", + 'java.vm.vendor': "Eclipse OpenJ9", + 'java.runtime.name': "IBM Semeru Runtime Open Edition", + 'java.runtime.version': "16.0.2+7" + ] + } + + private static Map semeruJvm17() { + ['java.home': "java-home", + 'java.version': "17.0.5", + 'java.vendor': "IBM Corporation", + 'os.arch': "x86_64", + 'java.vm.name': "Eclipse OpenJ9 VM", + 'java.vm.version': "openj9-0.35.0", + 'java.vm.vendor': "Eclipse OpenJ9", + 'java.runtime.name': "IBM Semeru Runtime Open Edition", + 'java.runtime.version': "17.0.5+8" + ] + } + +} diff --git a/subprojects/platform-jvm/src/test/groovy/org/gradle/jvm/toolchain/internal/JavaToolchainQueryServiceTest.groovy b/subprojects/platform-jvm/src/test/groovy/org/gradle/jvm/toolchain/internal/JavaToolchainQueryServiceTest.groovy index 4f0574a37b39..d2d99a288fc7 100644 --- a/subprojects/platform-jvm/src/test/groovy/org/gradle/jvm/toolchain/internal/JavaToolchainQueryServiceTest.groovy +++ b/subprojects/platform-jvm/src/test/groovy/org/gradle/jvm/toolchain/internal/JavaToolchainQueryServiceTest.groovy @@ -157,13 +157,13 @@ class JavaToolchainQueryServiceTest extends Specification { when: def filter = new DefaultToolchainSpec(TestUtil.objectFactory()) filter.languageVersion.set(JavaLanguageVersion.of(8)) - filter.vendor.set(JvmVendorSpec.IBM_SEMERU) + filter.vendor.set(JvmVendorSpec.IBM) def toolchain = queryService.findMatchingToolchain(filter) then: toolchain.isPresent() - toolchain.get().metadata.vendor.knownVendor == JvmVendor.KnownJvmVendor.IBM_SEMERU - toolchain.get().vendor == "IBM Semeru Runtimes" + toolchain.get().metadata.vendor.knownVendor == JvmVendor.KnownJvmVendor.IBM + toolchain.get().vendor == "IBM" } def "ignores invalid toolchains when finding a matching one"() { From 25e4fa7724f90427f7a7d93904aecafb2c4d3803 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B3zsef=20Bart=C3=B3k?= Date: Mon, 12 Dec 2022 15:20:40 +0200 Subject: [PATCH 09/17] Fix test --- .../install/internal/AdoptOpenJdkRemoteBinaryTest.groovy | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/subprojects/platform-jvm/src/test/groovy/org/gradle/jvm/toolchain/install/internal/AdoptOpenJdkRemoteBinaryTest.groovy b/subprojects/platform-jvm/src/test/groovy/org/gradle/jvm/toolchain/install/internal/AdoptOpenJdkRemoteBinaryTest.groovy index 09cbfcaa8c85..91da7e595df1 100644 --- a/subprojects/platform-jvm/src/test/groovy/org/gradle/jvm/toolchain/install/internal/AdoptOpenJdkRemoteBinaryTest.groovy +++ b/subprojects/platform-jvm/src/test/groovy/org/gradle/jvm/toolchain/install/internal/AdoptOpenJdkRemoteBinaryTest.groovy @@ -133,10 +133,14 @@ class AdoptOpenJdkRemoteBinaryTest extends Specification { then: download.isPresent() - download.get().getUri() == URI.create("https://api.adoptopenjdk.net/v3/binary/latest/12/ga/mac/x64/jdk/hotspot/normal/adoptopenjdk") + download.get().getUri() == URI.create("https://api.adoptopenjdk.net/v3/binary/latest/12/ga/mac/x64/jdk/${implementation}/normal/adoptopenjdk") where: - vendor << [JvmVendorSpec.ADOPTOPENJDK, JvmVendorSpec.IBM, JvmVendorSpec.matching("adoptopenjdk"), DefaultJvmVendorSpec.any()] + vendor | implementation + JvmVendorSpec.IBM | "openj9" + JvmVendorSpec.ADOPTOPENJDK | "hotspot" + JvmVendorSpec.matching("adoptopenjdk") | "hotspot" + DefaultJvmVendorSpec.any() | "hotspot" } def "can provide j9 impl if requested"() { From 1d3e8ed9d6d4bd855962bf60e2aaf82b4798a91b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A1lint=20Hegyi?= Date: Wed, 7 Dec 2022 10:20:36 +0000 Subject: [PATCH 10/17] Remove exceptional M1 Mac toolchain handling --- build-logic-commons/gradle-plugin/src/main/kotlin/common.kt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/build-logic-commons/gradle-plugin/src/main/kotlin/common.kt b/build-logic-commons/gradle-plugin/src/main/kotlin/common.kt index 4bdc23486f97..c1f4c5b55abc 100644 --- a/build-logic-commons/gradle-plugin/src/main/kotlin/common.kt +++ b/build-logic-commons/gradle-plugin/src/main/kotlin/common.kt @@ -20,9 +20,5 @@ import org.gradle.jvm.toolchain.JvmVendorSpec fun JavaPluginExtension.configureJavaToolChain() { toolchain { languageVersion.set(JavaLanguageVersion.of(11)) - // Do not force Adoptium vendor for M1 Macs - if (System.getProperty("os.arch") != "aarch64") { - vendor.set(JvmVendorSpec.ADOPTIUM) - } } } From 11d46ae4fb786d3c9ccddd03c44f447f73ad14d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B3zsef=20Bart=C3=B3k?= Date: Wed, 14 Dec 2022 13:12:18 +0200 Subject: [PATCH 11/17] Do not expose named domain object list (backport #23050 & #23112) --- .../gradle/api/internal/SettingsInternal.java | 5 +- .../initialization/DefaultSettings.java | 18 ++- .../DefaultToolchainManagement.java | 16 ++- .../org/gradle/internal/FinalizableValue.java | 35 +++++ ...ependencyResolutionManagementInternal.java | 5 +- .../ToolchainManagementInternal.java | 26 ++++ .../configurations/ConfigurationInternal.java | 5 +- .../DefaultConfigurationPublications.java | 5 +- ...ToolchainDownloadSpiIntegrationTest.groovy | 85 +++++++++++- .../JavaToolchainRepositoryHandler.java | 29 +++- ...DefaultJavaToolchainRepositoryHandler.java | 128 ++++++++++++++++-- .../DefaultJavaToolchainResolverRegistry.java | 13 +- .../DefaultJvmToolchainManagement.java | 7 +- ...avaToolchainRepositoryHandlerInternal.java | 23 ++++ ...JavaToolchainResolverRegistryInternal.java | 3 +- 15 files changed, 356 insertions(+), 47 deletions(-) create mode 100644 subprojects/core/src/main/java/org/gradle/internal/FinalizableValue.java create mode 100644 subprojects/core/src/main/java/org/gradle/internal/management/ToolchainManagementInternal.java create mode 100644 subprojects/platform-jvm/src/main/java/org/gradle/jvm/toolchain/internal/JavaToolchainRepositoryHandlerInternal.java diff --git a/subprojects/core/src/main/java/org/gradle/api/internal/SettingsInternal.java b/subprojects/core/src/main/java/org/gradle/api/internal/SettingsInternal.java index c1d97051d4ef..da0b84f63751 100644 --- a/subprojects/core/src/main/java/org/gradle/api/internal/SettingsInternal.java +++ b/subprojects/core/src/main/java/org/gradle/api/internal/SettingsInternal.java @@ -25,12 +25,13 @@ import org.gradle.groovy.scripts.ScriptSource; import org.gradle.initialization.DefaultProjectDescriptor; import org.gradle.initialization.IncludedBuildSpec; +import org.gradle.internal.FinalizableValue; import org.gradle.internal.management.DependencyResolutionManagementInternal; import org.gradle.internal.service.ServiceRegistry; import java.util.List; -public interface SettingsInternal extends Settings, PluginAwareInternal { +public interface SettingsInternal extends Settings, PluginAwareInternal, FinalizableValue { String BUILD_SRC = "buildSrc"; @@ -69,7 +70,5 @@ public interface SettingsInternal extends Settings, PluginAwareInternal { @Override BuildCacheConfigurationInternal getBuildCache(); - void preventFromFurtherMutation(); - DependencyResolutionManagementInternal getDependencyResolutionManagement(); } diff --git a/subprojects/core/src/main/java/org/gradle/initialization/DefaultSettings.java b/subprojects/core/src/main/java/org/gradle/initialization/DefaultSettings.java index 26da9719a86b..d0020adbe97b 100644 --- a/subprojects/core/src/main/java/org/gradle/initialization/DefaultSettings.java +++ b/subprojects/core/src/main/java/org/gradle/initialization/DefaultSettings.java @@ -43,6 +43,7 @@ import org.gradle.internal.Actions; import org.gradle.internal.deprecation.DeprecationLogger; import org.gradle.internal.management.DependencyResolutionManagementInternal; +import org.gradle.internal.management.ToolchainManagementInternal; import org.gradle.internal.resource.TextUriResourceLoader; import org.gradle.internal.service.ServiceRegistry; import org.gradle.internal.service.scopes.ServiceRegistryFactory; @@ -77,6 +78,8 @@ public abstract class DefaultSettings extends AbstractPluginAware implements Set private final List includedBuildSpecs = new ArrayList<>(); private final DependencyResolutionManagementInternal dependencyResolutionManagement; + private final ToolchainManagementInternal toolchainManagement; + public DefaultSettings( ServiceRegistryFactory serviceRegistryFactory, GradleInternal gradle, @@ -97,6 +100,7 @@ public DefaultSettings( this.services = serviceRegistryFactory.createFor(this); this.rootProjectDescriptor = createProjectDescriptor(null, settingsDir.getName(), settingsDir); this.dependencyResolutionManagement = services.get(DependencyResolutionManagementInternal.class); + this.toolchainManagement = services.get(ToolchainManagementInternal.class); } @Override @@ -370,13 +374,14 @@ public void enableFeaturePreview(String name) { } @Override - public void dependencyResolutionManagement(Action dependencyResolutionConfiguration) { - dependencyResolutionConfiguration.execute(dependencyResolutionManagement); + public void preventFromFurtherMutation() { + dependencyResolutionManagement.preventFromFurtherMutation(); + toolchainManagement.preventFromFurtherMutation(); } @Override - public void preventFromFurtherMutation() { - dependencyResolutionManagement.preventFromFurtherMutation(); + public void dependencyResolutionManagement(Action dependencyResolutionConfiguration) { + dependencyResolutionConfiguration.execute(dependencyResolutionManagement); } @Override @@ -385,13 +390,12 @@ public DependencyResolutionManagementInternal getDependencyResolutionManagement( } @Override - @Inject public ToolchainManagement getToolchainManagement() { - throw new UnsupportedOperationException(); + return toolchainManagement; } @Override public void toolchainManagement(Action toolchainManagementConfiguration) { - toolchainManagementConfiguration.execute(getToolchainManagement()); + toolchainManagementConfiguration.execute(toolchainManagement); } } diff --git a/subprojects/core/src/main/java/org/gradle/initialization/DefaultToolchainManagement.java b/subprojects/core/src/main/java/org/gradle/initialization/DefaultToolchainManagement.java index d303dec60692..a840ccb306a7 100644 --- a/subprojects/core/src/main/java/org/gradle/initialization/DefaultToolchainManagement.java +++ b/subprojects/core/src/main/java/org/gradle/initialization/DefaultToolchainManagement.java @@ -16,7 +16,19 @@ package org.gradle.initialization; -import org.gradle.api.toolchain.management.ToolchainManagement; +import org.gradle.api.internal.plugins.ExtensionContainerInternal; +import org.gradle.internal.FinalizableValue; +import org.gradle.internal.management.ToolchainManagementInternal; + +public abstract class DefaultToolchainManagement implements ToolchainManagementInternal { + + @Override + public void preventFromFurtherMutation() { + ExtensionContainerInternal extensions = (ExtensionContainerInternal) getExtensions(); + extensions.getAsMap().values().stream() + .filter(ext -> ext instanceof FinalizableValue) + .map(ext -> (FinalizableValue) ext) + .forEach(FinalizableValue::preventFromFurtherMutation); + } -public abstract class DefaultToolchainManagement implements ToolchainManagement { } diff --git a/subprojects/core/src/main/java/org/gradle/internal/FinalizableValue.java b/subprojects/core/src/main/java/org/gradle/internal/FinalizableValue.java new file mode 100644 index 000000000000..34676ccd0a85 --- /dev/null +++ b/subprojects/core/src/main/java/org/gradle/internal/FinalizableValue.java @@ -0,0 +1,35 @@ +/* + * Copyright 2022 the original author or authors. + * + * 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 org.gradle.internal; + +/** + * Mutable value type for which mutation can be disabled at a certain point in time, + * by calling the {@code disableFurtherMutations()} method. + *

+ * After {@code disableFurtherMutations()} has been called, any subsequent calls to methods that mutate + * the value in any way will fail by throwing an {@code IllegalStateException}. + */ +public interface FinalizableValue { + + /** + * Disallows further changes to the value represented by this type. + *

+ * Subsequent calls to methods that mutate the value in any way will fail by throwing an {@code IllegalStateException}. + */ + void preventFromFurtherMutation(); + +} diff --git a/subprojects/core/src/main/java/org/gradle/internal/management/DependencyResolutionManagementInternal.java b/subprojects/core/src/main/java/org/gradle/internal/management/DependencyResolutionManagementInternal.java index 07e0482b36ef..544b6df56df4 100644 --- a/subprojects/core/src/main/java/org/gradle/internal/management/DependencyResolutionManagementInternal.java +++ b/subprojects/core/src/main/java/org/gradle/internal/management/DependencyResolutionManagementInternal.java @@ -22,18 +22,17 @@ import org.gradle.api.initialization.resolve.RulesMode; import org.gradle.api.internal.project.ProjectInternal; import org.gradle.api.provider.Property; +import org.gradle.internal.FinalizableValue; import org.gradle.internal.service.scopes.Scopes; import org.gradle.internal.service.scopes.ServiceScope; import java.util.List; @ServiceScope(Scopes.Build.class) -public interface DependencyResolutionManagementInternal extends DependencyResolutionManagement { +public interface DependencyResolutionManagementInternal extends DependencyResolutionManagement, FinalizableValue { void configureProject(ProjectInternal project); - void preventFromFurtherMutation(); - void applyRules(ComponentMetadataHandler target); RepositoriesModeInternal getConfiguredRepositoriesMode(); diff --git a/subprojects/core/src/main/java/org/gradle/internal/management/ToolchainManagementInternal.java b/subprojects/core/src/main/java/org/gradle/internal/management/ToolchainManagementInternal.java new file mode 100644 index 000000000000..d2ba3270d9ca --- /dev/null +++ b/subprojects/core/src/main/java/org/gradle/internal/management/ToolchainManagementInternal.java @@ -0,0 +1,26 @@ +/* + * Copyright 2022 the original author or authors. + * + * 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 org.gradle.internal.management; + +import org.gradle.api.toolchain.management.ToolchainManagement; +import org.gradle.internal.FinalizableValue; +import org.gradle.internal.service.scopes.Scopes; +import org.gradle.internal.service.scopes.ServiceScope; + +@ServiceScope(Scopes.Build.class) +public interface ToolchainManagementInternal extends ToolchainManagement, FinalizableValue { +} diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/configurations/ConfigurationInternal.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/configurations/ConfigurationInternal.java index 51e5a6e36020..c53b361c08bc 100644 --- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/configurations/ConfigurationInternal.java +++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/configurations/ConfigurationInternal.java @@ -27,6 +27,7 @@ import org.gradle.api.internal.attributes.AttributeContainerInternal; import org.gradle.api.internal.attributes.ImmutableAttributes; import org.gradle.internal.DisplayName; +import org.gradle.internal.FinalizableValue; import org.gradle.internal.deprecation.DeprecatableConfiguration; import org.gradle.util.Path; @@ -36,7 +37,7 @@ import java.util.Set; import java.util.function.Supplier; -public interface ConfigurationInternal extends ResolveContext, Configuration, DeprecatableConfiguration, DependencyMetaDataProvider { +public interface ConfigurationInternal extends ResolveContext, Configuration, DeprecatableConfiguration, DependencyMetaDataProvider, FinalizableValue { enum InternalState { UNRESOLVED, BUILD_DEPENDENCIES_RESOLVED, @@ -88,8 +89,6 @@ enum InternalState { boolean isCanBeMutated(); - void preventFromFurtherMutation(); - /** * Reports whether this configuration uses {@link org.gradle.api.Incubating Incubating} attributes types, such as {@link org.gradle.api.attributes.Category#VERIFICATION}. * @return diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/configurations/DefaultConfigurationPublications.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/configurations/DefaultConfigurationPublications.java index 98f3ea3ea0e1..be5fb0e2658d 100644 --- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/configurations/DefaultConfigurationPublications.java +++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/configurations/DefaultConfigurationPublications.java @@ -37,6 +37,7 @@ import org.gradle.api.internal.file.FileCollectionFactory; import org.gradle.api.provider.Provider; import org.gradle.internal.DisplayName; +import org.gradle.internal.FinalizableValue; import org.gradle.internal.reflect.Instantiator; import org.gradle.internal.typeconversion.NotationParser; @@ -46,7 +47,7 @@ import java.util.List; import java.util.Set; -public class DefaultConfigurationPublications implements ConfigurationPublications { +public class DefaultConfigurationPublications implements ConfigurationPublications, FinalizableValue { private final DisplayName displayName; private final PublishArtifactSet artifacts; private final PublishArtifactSetProvider allArtifacts; @@ -219,7 +220,7 @@ public Collection getCapabilities() { return capabilities == null ? Collections.emptyList() : ImmutableList.copyOf(capabilities); } - void preventFromFurtherMutation() { + public void preventFromFurtherMutation() { canCreate = false; if (variants != null) { for (ConfigurationVariant variant : variants) { diff --git a/subprojects/platform-jvm/src/integTest/groovy/org/gradle/jvm/toolchain/JavaToolchainDownloadSpiIntegrationTest.groovy b/subprojects/platform-jvm/src/integTest/groovy/org/gradle/jvm/toolchain/JavaToolchainDownloadSpiIntegrationTest.groovy index e22e1ecc0b55..945978777cd6 100644 --- a/subprojects/platform-jvm/src/integTest/groovy/org/gradle/jvm/toolchain/JavaToolchainDownloadSpiIntegrationTest.groovy +++ b/subprojects/platform-jvm/src/integTest/groovy/org/gradle/jvm/toolchain/JavaToolchainDownloadSpiIntegrationTest.groovy @@ -369,7 +369,7 @@ class JavaToolchainDownloadSpiIntegrationTest extends AbstractJavaToolchainDownl } } - println(\"\"\"Explicitly requested toolchains: \${toolchainManagement.jvm.getJavaRepositories().collect { it.getName() }}.\"\"\") + println(\"\"\"Explicitly requested toolchains: \${toolchainManagement.jvm.getJavaRepositories().getAsList().collect { it.getName() }}.\"\"\") """ buildFile << """ @@ -395,6 +395,81 @@ class JavaToolchainDownloadSpiIntegrationTest extends AbstractJavaToolchainDownl failure.getOutput().contains("Explicitly requested toolchains: [useless3, useless1].") } + @ToBeFixedForConfigurationCache(because = "Fails the build with an additional error") + def "created repository can be removed"() { + settingsFile << """ + ${applyToolchainResolverPlugin("UselessToolchainResolver1", uselessToolchainResolverCode("UselessToolchainResolver1"))} + ${applyToolchainResolverPlugin("UselessToolchainResolver2", uselessToolchainResolverCode("UselessToolchainResolver2"))} + ${applyToolchainResolverPlugin("UselessToolchainResolver3", uselessToolchainResolverCode("UselessToolchainResolver3"))} + toolchainManagement { + jvm { + javaRepositories { + repository('useless1') { + resolverClass = UselessToolchainResolver1 + } + repository('useless2') { + resolverClass = UselessToolchainResolver2 + } + repository('useless3') { + resolverClass = UselessToolchainResolver3 + } + } + } + } + + toolchainManagement.jvm.javaRepositories.remove('useless2') + + println(\"\"\"Explicitly requested toolchains: \${toolchainManagement.jvm.getJavaRepositories().getAsList().collect { it.getName() }}.\"\"\") + """ + + buildFile << """ + apply plugin: "java" + + java { + toolchain { + languageVersion = JavaLanguageVersion.of(99) + } + } + """ + + file("src/main/java/Foo.java") << "public class Foo {}" + + when: + failure = executer + .withTasks("compileJava") + .requireOwnGradleUserHomeDir() + .withToolchainDownloadEnabled() + .runWithFailure() + + then: + failure.getOutput().contains("Explicitly requested toolchains: [useless1, useless3].") + } + + def "cannot mutate repository rules after settings have been evaluated"() { + settingsFile << """ + ${applyToolchainResolverPlugin("UselessToolchainResolver", uselessToolchainResolverCode("UselessToolchainResolver"))} + toolchainManagement { + jvm { + javaRepositories { + repository('useless') { + resolverClass = UselessToolchainResolver + } + } + } + } + """ + + buildFile << """ + gradle.settings.toolchainManagement.jvm.javaRepositories.remove('useless') + """ + + when: + fails ":help" + + then: + failure.assertHasCause("Mutation of toolchain repositories declared in settings is only allowed during settings evaluation") + } + private static String customToolchainResolverCode() { """ import java.util.Optional; @@ -455,13 +530,13 @@ class JavaToolchainDownloadSpiIntegrationTest extends AbstractJavaToolchainDownl SystemInfo systemInfo = NativeServices.getInstance().get(SystemInfo.class) switch (systemInfo.architecture) { case SystemInfo.Architecture.i386: - return "x32"; + return "x32" case SystemInfo.Architecture.amd64: - return "x64"; + return "x64" case SystemInfo.Architecture.aarch64: - return "aarch64"; + return "aarch64" default: - return "unknown"; + return "unknown" } } diff --git a/subprojects/platform-jvm/src/main/java/org/gradle/jvm/toolchain/JavaToolchainRepositoryHandler.java b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/toolchain/JavaToolchainRepositoryHandler.java index c1c672e57eee..7570d106f81d 100644 --- a/subprojects/platform-jvm/src/main/java/org/gradle/jvm/toolchain/JavaToolchainRepositoryHandler.java +++ b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/toolchain/JavaToolchainRepositoryHandler.java @@ -18,7 +18,8 @@ import org.gradle.api.Action; import org.gradle.api.Incubating; -import org.gradle.api.NamedDomainObjectList; + +import java.util.List; /** * {@link org.gradle.api.NamedDomainObjectList} based handler for configuring an @@ -27,7 +28,7 @@ * @since 7.6 */ @Incubating -public interface JavaToolchainRepositoryHandler extends NamedDomainObjectList { +public interface JavaToolchainRepositoryHandler { /** * Utility method for creating a named {@link JavaToolchainRepository} based on @@ -35,4 +36,28 @@ public interface JavaToolchainRepositoryHandler extends NamedDomainObjectList configureAction); + /** + * Returns a list of repositories that have been added so far. The list order + * reflects the order in which the repositories have been declared. + * + * @since 7.6.1 + */ + List getAsList(); + + /** + * Returns the count of the repositories added so far. + * + * @since 7.6.1 + */ + int size(); + + /** + * Removes the repository with the given name. + *

+ * Returns true if a repository with the specified name exists and has been successfully removed, false otherwise. + * + * @since 7.6.1 + */ + boolean remove(String name); + } diff --git a/subprojects/platform-jvm/src/main/java/org/gradle/jvm/toolchain/internal/DefaultJavaToolchainRepositoryHandler.java b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/toolchain/internal/DefaultJavaToolchainRepositoryHandler.java index b601738c6ccc..8c29e371a169 100644 --- a/subprojects/platform-jvm/src/main/java/org/gradle/jvm/toolchain/internal/DefaultJavaToolchainRepositoryHandler.java +++ b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/toolchain/internal/DefaultJavaToolchainRepositoryHandler.java @@ -18,26 +18,35 @@ import org.gradle.api.Action; import org.gradle.api.GradleException; +import org.gradle.api.InvalidUserCodeException; import org.gradle.api.Namer; +import org.gradle.api.artifacts.repositories.AuthenticationContainer; +import org.gradle.api.artifacts.repositories.PasswordCredentials; +import org.gradle.api.credentials.Credentials; import org.gradle.api.internal.CollectionCallbackActionDecorator; import org.gradle.api.internal.DefaultNamedDomainObjectList; import org.gradle.api.internal.artifacts.repositories.AuthenticationSupporter; import org.gradle.api.model.ObjectFactory; +import org.gradle.api.provider.Property; import org.gradle.api.provider.ProviderFactory; import org.gradle.authentication.Authentication; import org.gradle.internal.authentication.AuthenticationSchemeRegistry; import org.gradle.internal.authentication.DefaultAuthenticationContainer; import org.gradle.internal.reflect.Instantiator; import org.gradle.jvm.toolchain.JavaToolchainRepository; -import org.gradle.jvm.toolchain.JavaToolchainRepositoryHandler; +import org.gradle.jvm.toolchain.JavaToolchainResolver; import javax.inject.Inject; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; import java.util.Map; +import java.util.stream.Collectors; -public class DefaultJavaToolchainRepositoryHandler extends DefaultNamedDomainObjectList - implements JavaToolchainRepositoryHandler { +public class DefaultJavaToolchainRepositoryHandler implements JavaToolchainRepositoryHandlerInternal { - private final JavaToolchainResolverRegistryInternal registry; + private final DefaultNamedDomainObjectList repositories; private final Instantiator instantiator; @@ -47,16 +56,21 @@ public class DefaultJavaToolchainRepositoryHandler extends DefaultNamedDomainObj private final AuthenticationSchemeRegistry authenticationSchemeRegistry; + private boolean mutable = true; + @Inject public DefaultJavaToolchainRepositoryHandler( - JavaToolchainResolverRegistryInternal registry, Instantiator instantiator, ObjectFactory objectFactory, ProviderFactory providerFactory, AuthenticationSchemeRegistry authenticationSchemeRegistry ) { - super(JavaToolchainRepository.class, instantiator, new RepositoryNamer(), CollectionCallbackActionDecorator.NOOP); - this.registry = registry; + this.repositories = new DefaultNamedDomainObjectList(JavaToolchainRepository.class, instantiator, new RepositoryNamer(), CollectionCallbackActionDecorator.NOOP) { + @Override + public String getTypeDisplayName() { + return "repository"; + } + }; this.instantiator = instantiator; this.objectFactory = objectFactory; this.providerFactory = providerFactory; @@ -72,6 +86,8 @@ public String determineName(JavaToolchainRepository repository) { @Override public void repository(String name, Action configureAction) { + assertMutable(); + DefaultAuthenticationContainer authenticationContainer = new DefaultAuthenticationContainer(instantiator, CollectionCallbackActionDecorator.NOOP); for (Map.Entry, Class> e : authenticationSchemeRegistry.getRegisteredSchemes().entrySet()) { authenticationContainer.registerBinding(e.getKey(), e.getValue()); @@ -81,14 +97,106 @@ public void repository(String name, Action conf DefaultJavaToolchainRepository repository = objectFactory.newInstance(DefaultJavaToolchainRepository.class, name, authenticationContainer, authenticationSupporter, providerFactory); configureAction.execute(repository); - boolean isNew = registry.getRepositories().add(repository); + boolean isNew = repositories.add(repository); if (!isNew) { throw new GradleException("Duplicate configuration for repository '" + name + "'."); } } @Override - public String getTypeDisplayName() { - return "repository"; + public List getAsList() { + ArrayList copy = repositories.stream() + .map(it -> (JavaToolchainRepositoryInternal) it) + .map(ImmutableJavaToolchainRepository::new) + .collect(Collectors.toCollection(ArrayList::new)); + return Collections.unmodifiableList(copy); + } + + @Override + public int size() { + return repositories.size(); + } + + @Override + public boolean remove(String name) { + assertMutable(); + + JavaToolchainRepository repository = repositories.findByName(name); + if (repository == null) { + return false; + } + + return repositories.remove(repository); + } + + @Override + public void preventFromFurtherMutation() { + this.mutable = false; } + + private void assertMutable() { + if (!mutable) { + throw new InvalidUserCodeException("Mutation of toolchain repositories declared in settings is only allowed during settings evaluation"); + } + } + + private static class ImmutableJavaToolchainRepository implements JavaToolchainRepositoryInternal { + + private final JavaToolchainRepositoryInternal delegate; + + public ImmutableJavaToolchainRepository(JavaToolchainRepositoryInternal delegate) { + this.delegate = delegate; + } + + @Override + public Collection getConfiguredAuthentication() { + return delegate.getConfiguredAuthentication(); + } + + @Override + public PasswordCredentials getCredentials() { + return delegate.getCredentials(); + } + + @Override + public T getCredentials(Class credentialsType) { + return delegate.getCredentials(credentialsType); + } + + @Override + public void credentials(Action action) { + throw new UnsupportedOperationException("Can't modify repositories through a read-only view"); + } + + @Override + public void credentials(Class credentialsType, Action action) { + throw new UnsupportedOperationException("Can't modify repositories through a read-only view"); + } + + @Override + public void credentials(Class credentialsType) { + throw new UnsupportedOperationException("Can't modify repositories through a read-only view"); + } + + @Override + public void authentication(Action action) { + throw new UnsupportedOperationException("Can't modify repositories through a read-only view"); + } + + @Override + public AuthenticationContainer getAuthentication() { + return delegate.getAuthentication(); + } + + @Override + public String getName() { + return delegate.getName(); + } + + @Override + public Property> getResolverClass() { + return delegate.getResolverClass(); + } + } + } diff --git a/subprojects/platform-jvm/src/main/java/org/gradle/jvm/toolchain/internal/DefaultJavaToolchainResolverRegistry.java b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/toolchain/internal/DefaultJavaToolchainResolverRegistry.java index 5489dc802d6e..a153a02ce9f0 100644 --- a/subprojects/platform-jvm/src/main/java/org/gradle/jvm/toolchain/internal/DefaultJavaToolchainResolverRegistry.java +++ b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/toolchain/internal/DefaultJavaToolchainResolverRegistry.java @@ -29,7 +29,6 @@ import org.gradle.internal.authentication.AuthenticationSchemeRegistry; import org.gradle.internal.reflect.Instantiator; import org.gradle.jvm.toolchain.JavaToolchainRepository; -import org.gradle.jvm.toolchain.JavaToolchainRepositoryHandler; import org.gradle.jvm.toolchain.JavaToolchainResolver; import javax.inject.Inject; @@ -47,7 +46,7 @@ public abstract class DefaultJavaToolchainResolverRegistry implements JavaToolch private final BuildServiceRegistry sharedServices; - private final DefaultJavaToolchainRepositoryHandler repositories; + private final DefaultJavaToolchainRepositoryHandler repositoryHandler; private final List realizedRepositories = new ArrayList<>(); @@ -62,12 +61,12 @@ public DefaultJavaToolchainResolverRegistry( AuthenticationSchemeRegistry authenticationSchemeRegistry ) { this.sharedServices = gradle.getSharedServices(); - this.repositories = objectFactory.newInstance(DefaultJavaToolchainRepositoryHandler.class, this, instantiator, objectFactory, providerFactory, authenticationSchemeRegistry); + this.repositoryHandler = objectFactory.newInstance(DefaultJavaToolchainRepositoryHandler.class, instantiator, objectFactory, providerFactory, authenticationSchemeRegistry); } @Override - public JavaToolchainRepositoryHandler getRepositories() { - return repositories; + public JavaToolchainRepositoryHandlerInternal getRepositories() { + return repositoryHandler; } @Override @@ -82,7 +81,7 @@ public void register(Class implementationTy @Override public List requestedRepositories() { - if (realizedRepositories.size() != repositories.size()) { + if (realizedRepositories.size() != repositoryHandler.size()) { realizeRepositories(); } return realizedRepositories; @@ -92,7 +91,7 @@ private void realizeRepositories() { realizedRepositories.clear(); Set> resolvers = new HashSet<>(); - for (JavaToolchainRepository repository : repositories) { + for (JavaToolchainRepository repository : repositoryHandler.getAsList()) { if (!resolvers.add(repository.getResolverClass().get())) { throw new GradleException("Duplicate configuration for repository implementation '" + repository.getResolverClass().get().getName() + "'."); } diff --git a/subprojects/platform-jvm/src/main/java/org/gradle/jvm/toolchain/internal/DefaultJvmToolchainManagement.java b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/toolchain/internal/DefaultJvmToolchainManagement.java index 59dae352c97b..783b570bb338 100644 --- a/subprojects/platform-jvm/src/main/java/org/gradle/jvm/toolchain/internal/DefaultJvmToolchainManagement.java +++ b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/toolchain/internal/DefaultJvmToolchainManagement.java @@ -17,12 +17,13 @@ package org.gradle.jvm.toolchain.internal; import org.gradle.api.Action; +import org.gradle.internal.FinalizableValue; import org.gradle.jvm.toolchain.JavaToolchainRepositoryHandler; import org.gradle.jvm.toolchain.JvmToolchainManagement; import javax.inject.Inject; -public abstract class DefaultJvmToolchainManagement implements JvmToolchainManagement { +public abstract class DefaultJvmToolchainManagement implements JvmToolchainManagement, FinalizableValue { private final JavaToolchainResolverRegistryInternal registry; @@ -41,4 +42,8 @@ public void javaRepositories(Action conf configureAction.execute(getJavaRepositories()); } + @Override + public void preventFromFurtherMutation() { + registry.getRepositories().preventFromFurtherMutation(); + } } diff --git a/subprojects/platform-jvm/src/main/java/org/gradle/jvm/toolchain/internal/JavaToolchainRepositoryHandlerInternal.java b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/toolchain/internal/JavaToolchainRepositoryHandlerInternal.java new file mode 100644 index 000000000000..069d2ae6e3bd --- /dev/null +++ b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/toolchain/internal/JavaToolchainRepositoryHandlerInternal.java @@ -0,0 +1,23 @@ +/* + * Copyright 2022 the original author or authors. + * + * 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 org.gradle.jvm.toolchain.internal; + +import org.gradle.internal.FinalizableValue; +import org.gradle.jvm.toolchain.JavaToolchainRepositoryHandler; + +public interface JavaToolchainRepositoryHandlerInternal extends JavaToolchainRepositoryHandler, FinalizableValue { +} diff --git a/subprojects/platform-jvm/src/main/java/org/gradle/jvm/toolchain/internal/JavaToolchainResolverRegistryInternal.java b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/toolchain/internal/JavaToolchainResolverRegistryInternal.java index e5c85cacf0b3..8448afe83bfc 100644 --- a/subprojects/platform-jvm/src/main/java/org/gradle/jvm/toolchain/internal/JavaToolchainResolverRegistryInternal.java +++ b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/toolchain/internal/JavaToolchainResolverRegistryInternal.java @@ -17,13 +17,12 @@ package org.gradle.jvm.toolchain.internal; import org.gradle.jvm.toolchain.JavaToolchainResolverRegistry; -import org.gradle.jvm.toolchain.JavaToolchainRepositoryHandler; import java.util.List; public interface JavaToolchainResolverRegistryInternal extends JavaToolchainResolverRegistry { - JavaToolchainRepositoryHandler getRepositories(); + JavaToolchainRepositoryHandlerInternal getRepositories(); List requestedRepositories(); } From 0a81dcb44a64c7af562e9d6703ad870c7c9abd87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B3zsef=20Bart=C3=B3k?= Date: Wed, 14 Dec 2022 13:32:55 +0200 Subject: [PATCH 12/17] Fix test --- .../jvm/toolchain/internal/JavaToolchainQueryServiceTest.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subprojects/platform-jvm/src/test/groovy/org/gradle/jvm/toolchain/internal/JavaToolchainQueryServiceTest.groovy b/subprojects/platform-jvm/src/test/groovy/org/gradle/jvm/toolchain/internal/JavaToolchainQueryServiceTest.groovy index 4f0574a37b39..4372dc3df3ff 100644 --- a/subprojects/platform-jvm/src/test/groovy/org/gradle/jvm/toolchain/internal/JavaToolchainQueryServiceTest.groovy +++ b/subprojects/platform-jvm/src/test/groovy/org/gradle/jvm/toolchain/internal/JavaToolchainQueryServiceTest.groovy @@ -287,7 +287,7 @@ class JavaToolchainQueryServiceTest extends Specification { then: def e = thrown(GradleException) - e.message == "Provisioned toolchain '${File.separator}path${File.separator}12.broken' could not be probed." + e.message == "Toolchain installation '${File.separator}path${File.separator}12.broken' could not be probed." } def "provisioned toolchain is cached no re-request"() { From d5fae0cf0f3044c3c3c42c413c67e69be7184a0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B3zsef=20Bart=C3=B3k?= Date: Wed, 14 Dec 2022 13:56:31 +0200 Subject: [PATCH 13/17] Fix deprecation message --- .../java/org/gradle/jvm/toolchain/JvmVendorSpec.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/subprojects/platform-jvm/src/main/java/org/gradle/jvm/toolchain/JvmVendorSpec.java b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/toolchain/JvmVendorSpec.java index 84d0ce811f16..3fa4289c195e 100644 --- a/subprojects/platform-jvm/src/main/java/org/gradle/jvm/toolchain/JvmVendorSpec.java +++ b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/toolchain/JvmVendorSpec.java @@ -34,10 +34,15 @@ public abstract class JvmVendorSpec { */ @Incubating public static final JvmVendorSpec ADOPTIUM = matching(KnownJvmVendor.ADOPTIUM); + public static final JvmVendorSpec ADOPTOPENJDK = matching(KnownJvmVendor.ADOPTOPENJDK); + public static final JvmVendorSpec AMAZON = matching(KnownJvmVendor.AMAZON); + public static final JvmVendorSpec APPLE = matching(KnownJvmVendor.APPLE); + public static final JvmVendorSpec AZUL = matching(KnownJvmVendor.AZUL); + public static final JvmVendorSpec BELLSOFT = matching(KnownJvmVendor.BELLSOFT); /** @@ -49,12 +54,14 @@ public abstract class JvmVendorSpec { public static final JvmVendorSpec GRAAL_VM = matching(KnownJvmVendor.GRAAL_VM); public static final JvmVendorSpec HEWLETT_PACKARD = matching(KnownJvmVendor.HEWLETT_PACKARD); + public static final JvmVendorSpec IBM = matching(KnownJvmVendor.IBM); + /** * A constant for using IBM Semeru Runtimes as the JVM vendor. * * @since 7.4 - * @deprecated All IBM runtimes are Semeru runtimes, so no point in having two separate vendor definitions. IBM should be used instead. + * @deprecated We are grouping all IBM runtimes under the '{@code IBM}' vendor, won't keep a separate constant for Semeru ones. Just use '{@code IBM}' instead. */ @Deprecated public static final JvmVendorSpec IBM_SEMERU = IBM; @@ -66,7 +73,9 @@ public abstract class JvmVendorSpec { */ @Incubating public static final JvmVendorSpec MICROSOFT = matching(KnownJvmVendor.MICROSOFT); + public static final JvmVendorSpec ORACLE = matching(KnownJvmVendor.ORACLE); + public static final JvmVendorSpec SAP = matching(KnownJvmVendor.SAP); /** From 55896a8e66353126951828b47e36a5fc61620013 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B3zsef=20Bart=C3=B3k?= Date: Wed, 14 Dec 2022 13:59:39 +0200 Subject: [PATCH 14/17] Reformat to one sentence per line --- .../migration/upgrading_version_7.adoc | 109 ++++++++++++------ 1 file changed, 72 insertions(+), 37 deletions(-) diff --git a/subprojects/docs/src/docs/userguide/migration/upgrading_version_7.adoc b/subprojects/docs/src/docs/userguide/migration/upgrading_version_7.adoc index f3c6f02ecd95..ba2871372864 100644 --- a/subprojects/docs/src/docs/userguide/migration/upgrading_version_7.adoc +++ b/subprojects/docs/src/docs/userguide/migration/upgrading_version_7.adoc @@ -15,7 +15,8 @@ [[upgrading_version_7]] = Upgrading your build from Gradle 7.x to the latest -This chapter provides the information you need to migrate your Gradle 7.x builds to the latest Gradle release. For migrating from Gradle 4.x, 5.x, or 6.x, see the <> first. +This chapter provides the information you need to migrate your Gradle 7.x builds to the latest Gradle release. +For migrating from Gradle 4.x, 5.x, or 6.x, see the <> first. We recommend the following steps for all users: @@ -28,7 +29,8 @@ This is so that you can see any deprecation warnings that apply to your build. Alternatively, you could run `gradle help --warning-mode=all` to see the deprecations in the console, though it may not report as much detailed information. . Update your plugins. + -Some plugins will break with this new version of Gradle, for example because they use internal APIs that have been removed or changed. The previous step will help you identify potential problems by issuing deprecation warnings when a plugin does try to use a deprecated part of the API. +Some plugins will break with this new version of Gradle, for example because they use internal APIs that have been removed or changed. +The previous step will help you identify potential problems by issuing deprecation warnings when a plugin does try to use a deprecated part of the API. + . Run `gradle wrapper --gradle-version {gradleVersion}` to update the project to {gradleVersion}. . Try to run the project and debug any errors using the <>. @@ -166,7 +168,8 @@ Other syntax effected by this change includes: - You cannot use `Provider` as a dependency declaration. - You cannot use a `Map` as a dependency declaration for Kotlin or Java. -- You cannot use a bundle as a dependency declaration directly (`implementation(libs.bundles.testing)`). Use `implementation.bundle(libs.bundles.testing)` instead. +- You cannot use a bundle as a dependency declaration directly (`implementation(libs.bundles.testing)`). +Use `implementation.bundle(libs.bundles.testing)` instead. For more information, see the updated <> example in the JVM Test Suite Plugin section of the user guide and the link:{groovyDslPath}/org.gradle.api.artifacts.dsl.DependencyAdder.html[`DependencyAdder`] page in the DSL reference. @@ -206,14 +209,18 @@ These members will be removed in Gradle 9.0. [[dependency_factory_renamed]] ==== Internal DependencyFactory was renamed -The internal `org.gradle.api.internal.artifacts.dsl.dependencies.DependencyFactory` type was renamed to `org.gradle.api.internal.artifacts.dsl.dependencies.DependencyFactoryInternal`. As an internal type, it should not be used, but for compatibility reasons the inner `ClassPathNotation` type is still available. This name for the type is deprecated and will be removed in Gradle 8.0. The public API for this is on `DependencyHandler`, with methods such as `localGroovy()` providing the same functionality. +The internal `org.gradle.api.internal.artifacts.dsl.dependencies.DependencyFactory` type was renamed to `org.gradle.api.internal.artifacts.dsl.dependencies.DependencyFactoryInternal`. +As an internal type, it should not be used, but for compatibility reasons the inner `ClassPathNotation` type is still available. +This name for the type is deprecated and will be removed in Gradle 8.0. +The public API for this is on `DependencyHandler`, with methods such as `localGroovy()` providing the same functionality. ==== Replacement collections in `org.gradle.plugins.ide.idea.model.IdeaModule` The `testResourcesDirs` and `testSourcesDirs` fields and their getters and setters have been deprecated. Replace usages with the now stable `getTestSources()` and `getTestResources()` methods and their respective setters. These new methods return and are backed by `ConfigurableFileCollection` instances for improved flexibility of use. -Gradle now warns upon usage of these deprecated methods. They will be removed in a future version of Gradle. +Gradle now warns upon usage of these deprecated methods. +They will be removed in a future version of Gradle. ==== Replacement methods in `org.gradle.api.tasks.testing.TestReport` @@ -348,7 +355,8 @@ Alternatively, you can adjust or remove classpath attributes in the `eclipse.cla ==== Signing plugin defaults to `gpg` instead of `gpg2` when using the GPG command -The signature plugin's default executable link:signing_plugin.html#sec:using_gpg_agent[when using the GPG command] changed from `gpg2` to `gpg`. The change was motivated as GPG 2.x became stable, and distributions started to migrate by not linking the `gpg2` executable. +The signature plugin's default executable link:signing_plugin.html#sec:using_gpg_agent[when using the GPG command] changed from `gpg2` to `gpg`. +The change was motivated as GPG 2.x became stable, and distributions started to migrate by not linking the `gpg2` executable. In order to set the old default, the executable can be manually defined in `gradle.properties`: @@ -427,11 +435,15 @@ Due to that, if you use `zincVersion` setting it's advised to remove it and only ==== Removes implicit `--add-opens` for test workers -Prior to Gradle 7.5, JDK modules `java.base/java.util` and `java.base/java.lang` were automatically opened in test workers on JDK9+ by passing `--add-opens` CLI arguments. This meant any tests were able to perform deep reflection on JDK internals without warning or failing. This caused tests to be unreliable by allowing code to pass when it would otherwise fail in a production environment. +Prior to Gradle 7.5, JDK modules `java.base/java.util` and `java.base/java.lang` were automatically opened in test workers on JDK9+ by passing `--add-opens` CLI arguments. +This meant any tests were able to perform deep reflection on JDK internals without warning or failing. +This caused tests to be unreliable by allowing code to pass when it would otherwise fail in a production environment. -These implicit arguments have been removed and are no longer added by default. If your code or any of your dependencies are performing deep reflection into JDK internals during test execution, you may see the following behavior changes: +These implicit arguments have been removed and are no longer added by default. +If your code or any of your dependencies are performing deep reflection into JDK internals during test execution, you may see the following behavior changes: -Before Java 16, new build warnings are shown. These new warnings are printed to stderr and will not fail the build: +Before Java 16, new build warnings are shown. +These new warnings are printed to stderr and will not fail the build: ``` WARNING: An illegal reflective access operation has occurred WARNING: Illegal reflective access by com.google.inject.internal.cglib.core.ReflectUtils$2 (file:/.../testng-5.12.1.jar) to @@ -460,7 +472,8 @@ org.gradle.api.GradleException: Could not inject synthetic classes. Caused by: java.lang.RuntimeException: java.lang.IllegalAccessException: module java.base does not open java.lang to unnamed module @1e92bd61 ``` -In most cases, these errors can be resolved by updating the code or dependency performing the illegal access. If the code-under-test or the newest version of the dependency in question performs illegal access by design, the old behavior can be restored by opening the `java.base/java.lang` and `java.base/java.util` modules manually with `--add-opens`: +In most cases, these errors can be resolved by updating the code or dependency performing the illegal access. +If the code-under-test or the newest version of the dependency in question performs illegal access by design, the old behavior can be restored by opening the `java.base/java.lang` and `java.base/java.util` modules manually with `--add-opens`: ``` tasks.withType(Test).configureEach { @@ -469,23 +482,29 @@ tasks.withType(Test).configureEach { } ``` -If you are developing Gradle plugins, `ProjectBuilder` relies on reflection in the `java.base/java.lang` module. Gradle will automatically add the appropriate `--add-opens` flag to tests when the `java-gradle-plugin` plugin is applied. +If you are developing Gradle plugins, `ProjectBuilder` relies on reflection in the `java.base/java.lang` module. +Gradle will automatically add the appropriate `--add-opens` flag to tests when the `java-gradle-plugin` plugin is applied. -If you are using TestNG, versions prior to `5.14.6` perform illegal reflection. Updating to at least `5.14.6` should fix the incompatibility. +If you are using TestNG, versions prior to `5.14.6` perform illegal reflection. +Updating to at least `5.14.6` should fix the incompatibility. [[checkstyle_worker_api]] ==== Checkstyle tasks use toolchains and execute in parallel by default The <> now uses the Gradle worker API to run Checkstyle as an external worker process, so that multiple Checkstyle tasks may now run in parallel within a project. -Since Checkstyle runs as an external process you can control the memory via the `minHeapSize` and `maxHeapSize` properties on the Checkstyle tasks. In case of out of memory errors, increasing the max memory via the `maxHeapSize` property should solve the issue. By default, the process will start with `maxHeapSize` of 512MB. We also recommend to update Checkstyle to version 9.3 or later. +Since Checkstyle runs as an external process you can control the memory via the `minHeapSize` and `maxHeapSize` properties on the Checkstyle tasks. +In case of out of memory errors, increasing the max memory via the `maxHeapSize` property should solve the issue. +By default, the process will start with `maxHeapSize` of 512MB. +We also recommend to update Checkstyle to version 9.3 or later. ==== Missing files specified with relative paths when running Checkstyle Gradle 7.5 consistently sets the current working directory for the Checkstyle task to `GRADLE_USER_HOME/workers`. This may cause problems with custom Checkstyle tasks or Checkstyle configuration files that assume a different directory for relative paths. -Previously, Gradle selected the current working directory based on the directory where you ran Gradle. If you ran Gradle in: +Previously, Gradle selected the current working directory based on the directory where you ran Gradle. +If you ran Gradle in: - the root directory of a project: Gradle uses the root directory as the current working directory. - a nested directory of a project: Gradle uses the root directory of the subproject as the current working directory. @@ -505,8 +524,8 @@ Using a file collection with paths which contain a path separator may lead to in [[dependencyinsight_singlepath]] ==== `dependencyInsight` `--singlepath` option is deprecated -For consistency, this was changed to `--single-path`. The API -method has remained the same, this only affects the CLI. +For consistency, this was changed to `--single-path`. +The API method has remained the same, this only affects the CLI. [[groovydoc_option_improvements]] ==== Groovydoc `includePrivate` property is deprecated @@ -538,7 +557,8 @@ Following the move from AdoptOpenJDK to Adoptium, under the Eclipse foundation, Instead, an Eclipse Temurin or IBM Semeru build is returned. Gradle 7.4+ will now emit a deprecation warning when the AdoptOpenJDK vendor is specified in the <> and it is used by auto provisioning. -If you must use AdoptOpenJDK, you should turn off auto-download. If an Eclipse Temurin or IBM Semeru build works for you, specify `JvmVendorSpec.ADOPTIUM` or `JvmVendorSpec.IBM` as the vendor or leave the vendor unspecified. +If you must use AdoptOpenJDK, you should turn off auto-download. +If an Eclipse Temurin or IBM Semeru build works for you, specify `JvmVendorSpec.ADOPTIUM` or `JvmVendorSpec.IBM` as the vendor or leave the vendor unspecified. [[empty_directories_file_tree]] ==== File trees and empty directory handling @@ -559,8 +579,8 @@ The same is true for `link:{javadocPath}/org/gradle/api/tasks/TaskInputs.html#di ==== Using LazyPublishArtifact without a FileResolver is deprecated When using a LazyPublishArtifact without a FileResolver, a different file resolution strategy is used, which duplicates -some logic in the FileResolver. To improve consistency, LazyPublishArtifact should be used with a FileResolver, and will -require it in the future. +some logic in the FileResolver. +To improve consistency, LazyPublishArtifact should be used with a FileResolver, and will require it in the future. This also affects other internal APIs that use LazyPublishArtifact, which now also have deprecation warnings where needed. @@ -577,20 +597,23 @@ This way, Gradle is able to apply optimizations like up-to-date checks instead o [[unique_attribute_sets]] ==== Unique attribute sets -The set of link:{javadocPath}/org/gradle/api/attribute/Attribute.html[Attribute]s associated with a _consumable_ configuration within a project, must be unique across all other configurations within that project which share the same set of link:{javadocPath}/org/gradle/api/capabilities/Capability.html[Capability]s. This will be checked at the end of configuring variant configurations, as they are locked against further mutation. +The set of link:{javadocPath}/org/gradle/api/attribute/Attribute.html[Attribute]s associated with a _consumable_ configuration within a project, must be unique across all other configurations within that project which share the same set of link:{javadocPath}/org/gradle/api/capabilities/Capability.html[Capability]s. +This will be checked at the end of configuring variant configurations, as they are locked against further mutation. If the set of attributes is shared across configurations, consider adding an additional attribute to one of the variants for the sole purpose of disambiguation. [[for_use_at_configuration_time_deprecation]] ==== `Provider#forUseAtConfigurationTime()` has been deprecated -link:{javadocPath}/org/gradle/api/provider/Provider.html#forUseAtConfigurationTime--[Provider#forUseAtConfigurationTime] is now deprecated and scheduled for removal in Gradle 9.0. Clients should simply remove the call. +link:{javadocPath}/org/gradle/api/provider/Provider.html#forUseAtConfigurationTime--[Provider#forUseAtConfigurationTime] is now deprecated and scheduled for removal in Gradle 9.0. +Clients should simply remove the call. The call was mandatory on providers of external values such as link:{javadocPath}/org/gradle/api/provider/ProviderFactory.html#systemProperty-java.lang.String-[system properties], link:{javadocPath}/org/gradle/api/provider/ProviderFactory.html#environmentVariable-java.lang.String-[environment variables], link:{javadocPath}/org/gradle/api/provider/ProviderFactory.html#gradleProperty-java.lang.String-[Gradle properties] and link:{javadocPath}/org/gradle/api/provider/ProviderFactory.html#fileContents-org.gradle.api.file.RegularFile-[file contents] meant to be used at configuration time together with the configuration cache feature. Starting with version 7.4 Gradle will implicitly treat an external value used at configuration time as a configuration cache input. -Clients are also free to use standard Java APIs such as `System#getenv` to read environment variables, `System#getProperty` to read system properties as well as Gradle APIs such as link:{javadocPath}/org/gradle/api/provider/ProviderFactory.html#systemProperty-java.lang.String-[`Project#property(String)`] and link:{javadocPath}/org/gradle/api/Project.html#findProperty-java.lang.String-[`Project#findProperty(String)`] to read Gradle properties at configuration time. The `Provider` based APIs are still the recommended way to connect external values to task inputs for maximum configuration cache reuse. +Clients are also free to use standard Java APIs such as `System#getenv` to read environment variables, `System#getProperty` to read system properties as well as Gradle APIs such as link:{javadocPath}/org/gradle/api/provider/ProviderFactory.html#systemProperty-java.lang.String-[`Project#property(String)`] and link:{javadocPath}/org/gradle/api/Project.html#findProperty-java.lang.String-[`Project#findProperty(String)`] to read Gradle properties at configuration time. +The `Provider` based APIs are still the recommended way to connect external values to task inputs for maximum configuration cache reuse. ==== `ConfigurableReport#setDestination(org.gradle.api.provider.Provider)` has been deprecated @@ -620,8 +643,8 @@ these usages to APIs that are supported by the configuration cache. [[build_finished_events]] ==== Build finished events -Build finished listeners are not supported by the Gradle configuration cache. And so, the following API are deprecated and will be -removed in Gradle 8.0: +Build finished listeners are not supported by the Gradle configuration cache. +And so, the following API are deprecated and will be removed in Gradle 8.0: - Method link:{javadocPath}/org/gradle/api/invocation/Gradle.html#buildFinished-org.gradle.api.Action-[Gradle.buildFinished()] - Method link:{javadocPath}/org/gradle/BuildListener.html#buildFinished-org.gradle.BuildResult-[BuildListener.buildFinished()] @@ -661,7 +684,8 @@ Check the < Date: Wed, 14 Dec 2022 14:06:58 +0200 Subject: [PATCH 15/17] Revert some unnecessary changes --- .../main/java/org/gradle/api/internal/SettingsInternal.java | 5 +++-- .../artifacts/configurations/ConfigurationInternal.java | 5 +++-- .../configurations/DefaultConfigurationPublications.java | 5 ++--- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/subprojects/core/src/main/java/org/gradle/api/internal/SettingsInternal.java b/subprojects/core/src/main/java/org/gradle/api/internal/SettingsInternal.java index da0b84f63751..c1d97051d4ef 100644 --- a/subprojects/core/src/main/java/org/gradle/api/internal/SettingsInternal.java +++ b/subprojects/core/src/main/java/org/gradle/api/internal/SettingsInternal.java @@ -25,13 +25,12 @@ import org.gradle.groovy.scripts.ScriptSource; import org.gradle.initialization.DefaultProjectDescriptor; import org.gradle.initialization.IncludedBuildSpec; -import org.gradle.internal.FinalizableValue; import org.gradle.internal.management.DependencyResolutionManagementInternal; import org.gradle.internal.service.ServiceRegistry; import java.util.List; -public interface SettingsInternal extends Settings, PluginAwareInternal, FinalizableValue { +public interface SettingsInternal extends Settings, PluginAwareInternal { String BUILD_SRC = "buildSrc"; @@ -70,5 +69,7 @@ public interface SettingsInternal extends Settings, PluginAwareInternal, Finaliz @Override BuildCacheConfigurationInternal getBuildCache(); + void preventFromFurtherMutation(); + DependencyResolutionManagementInternal getDependencyResolutionManagement(); } diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/configurations/ConfigurationInternal.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/configurations/ConfigurationInternal.java index c53b361c08bc..51e5a6e36020 100644 --- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/configurations/ConfigurationInternal.java +++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/configurations/ConfigurationInternal.java @@ -27,7 +27,6 @@ import org.gradle.api.internal.attributes.AttributeContainerInternal; import org.gradle.api.internal.attributes.ImmutableAttributes; import org.gradle.internal.DisplayName; -import org.gradle.internal.FinalizableValue; import org.gradle.internal.deprecation.DeprecatableConfiguration; import org.gradle.util.Path; @@ -37,7 +36,7 @@ import java.util.Set; import java.util.function.Supplier; -public interface ConfigurationInternal extends ResolveContext, Configuration, DeprecatableConfiguration, DependencyMetaDataProvider, FinalizableValue { +public interface ConfigurationInternal extends ResolveContext, Configuration, DeprecatableConfiguration, DependencyMetaDataProvider { enum InternalState { UNRESOLVED, BUILD_DEPENDENCIES_RESOLVED, @@ -89,6 +88,8 @@ enum InternalState { boolean isCanBeMutated(); + void preventFromFurtherMutation(); + /** * Reports whether this configuration uses {@link org.gradle.api.Incubating Incubating} attributes types, such as {@link org.gradle.api.attributes.Category#VERIFICATION}. * @return diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/configurations/DefaultConfigurationPublications.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/configurations/DefaultConfigurationPublications.java index be5fb0e2658d..98f3ea3ea0e1 100644 --- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/configurations/DefaultConfigurationPublications.java +++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/configurations/DefaultConfigurationPublications.java @@ -37,7 +37,6 @@ import org.gradle.api.internal.file.FileCollectionFactory; import org.gradle.api.provider.Provider; import org.gradle.internal.DisplayName; -import org.gradle.internal.FinalizableValue; import org.gradle.internal.reflect.Instantiator; import org.gradle.internal.typeconversion.NotationParser; @@ -47,7 +46,7 @@ import java.util.List; import java.util.Set; -public class DefaultConfigurationPublications implements ConfigurationPublications, FinalizableValue { +public class DefaultConfigurationPublications implements ConfigurationPublications { private final DisplayName displayName; private final PublishArtifactSet artifacts; private final PublishArtifactSetProvider allArtifacts; @@ -220,7 +219,7 @@ public Collection getCapabilities() { return capabilities == null ? Collections.emptyList() : ImmutableList.copyOf(capabilities); } - public void preventFromFurtherMutation() { + void preventFromFurtherMutation() { canCreate = false; if (variants != null) { for (ConfigurationVariant variant : variants) { From 573527633e3fc7d4ae256e514a3823fb8e896df6 Mon Sep 17 00:00:00 2001 From: Bo Zhang Date: Wed, 7 Dec 2022 18:10:26 +0800 Subject: [PATCH 16/17] Ignore failing M9JavaConfigurabilityCrossVersionSpec on Gradle 2.x For some reason M9JavaConfigurabilityCrossVersionSpec is failing on Gradle 2.x, which is too old. Let's simply ignore it on Gradle 2.x. --- .../tooling/m9/M9JavaConfigurabilityCrossVersionSpec.groovy | 2 ++ 1 file changed, 2 insertions(+) diff --git a/subprojects/tooling-api/src/crossVersionTest/groovy/org/gradle/integtests/tooling/m9/M9JavaConfigurabilityCrossVersionSpec.groovy b/subprojects/tooling-api/src/crossVersionTest/groovy/org/gradle/integtests/tooling/m9/M9JavaConfigurabilityCrossVersionSpec.groovy index d54fec331126..66a75779d053 100644 --- a/subprojects/tooling-api/src/crossVersionTest/groovy/org/gradle/integtests/tooling/m9/M9JavaConfigurabilityCrossVersionSpec.groovy +++ b/subprojects/tooling-api/src/crossVersionTest/groovy/org/gradle/integtests/tooling/m9/M9JavaConfigurabilityCrossVersionSpec.groovy @@ -17,12 +17,14 @@ package org.gradle.integtests.tooling.m9 import org.gradle.integtests.fixtures.AvailableJavaHomes +import org.gradle.integtests.tooling.fixture.TargetGradleVersion import org.gradle.integtests.tooling.fixture.TextUtil import org.gradle.integtests.tooling.fixture.ToolingApiSpecification import org.gradle.tooling.model.GradleProject import org.gradle.tooling.model.build.BuildEnvironment import org.junit.Assume +@TargetGradleVersion(">=3.0") class M9JavaConfigurabilityCrossVersionSpec extends ToolingApiSpecification { def setup() { From ec424d68df74e72d0ea379c644efb60b0899853a Mon Sep 17 00:00:00 2001 From: Gary Hale Date: Fri, 16 Dec 2022 15:09:09 -0500 Subject: [PATCH 17/17] Fix issue with ant builder throwing exception on call() --- .../CallablePropertyIntegrationTest.groovy | 16 ++++++++++++++++ ...nClosurePropertiesAsMethodsDynamicObject.java | 4 +++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/subprojects/model-core/src/integTest/groovy/org/gradle/internal/extensibility/CallablePropertyIntegrationTest.groovy b/subprojects/model-core/src/integTest/groovy/org/gradle/internal/extensibility/CallablePropertyIntegrationTest.groovy index e5a53c463632..552e4ad5ef4b 100644 --- a/subprojects/model-core/src/integTest/groovy/org/gradle/internal/extensibility/CallablePropertyIntegrationTest.groovy +++ b/subprojects/model-core/src/integTest/groovy/org/gradle/internal/extensibility/CallablePropertyIntegrationTest.groovy @@ -18,6 +18,7 @@ package org.gradle.internal.extensibility import org.gradle.integtests.fixtures.AbstractIntegrationSpec +import spock.lang.Issue class CallablePropertyIntegrationTest extends AbstractIntegrationSpec { @@ -95,4 +96,19 @@ class CallablePropertyIntegrationTest extends AbstractIntegrationSpec { "Inside Project.configure" | "configure(container.foo) { prop() }" "Inside NDOC.configure" | "container.configure { foo { prop() } }" } + + @Issue('https://github.com/gradle/gradle/issues/23111') + def "can configure dynamic property without call method"() { + buildFile << """ + task test { + doLast { + ant { echo(message: 'hello world!') } + } + } + """ + + expect: + args('--stacktrace') + succeeds("test") + } } diff --git a/subprojects/model-core/src/main/java/org/gradle/internal/extensibility/MixInClosurePropertiesAsMethodsDynamicObject.java b/subprojects/model-core/src/main/java/org/gradle/internal/extensibility/MixInClosurePropertiesAsMethodsDynamicObject.java index a58375206b7c..4ba1f999c477 100644 --- a/subprojects/model-core/src/main/java/org/gradle/internal/extensibility/MixInClosurePropertiesAsMethodsDynamicObject.java +++ b/subprojects/model-core/src/main/java/org/gradle/internal/extensibility/MixInClosurePropertiesAsMethodsDynamicObject.java @@ -56,7 +56,9 @@ public DynamicInvokeResult tryInvokeMethod(String name, Object... arguments) { return DynamicInvokeResult.found(); } DynamicObject dynamicObject = DynamicObjectUtil.asDynamicObject(property); - return dynamicObject.tryInvokeMethod("call", arguments); + if (dynamicObject.hasMethod("call", arguments)) { + return dynamicObject.tryInvokeMethod("call", arguments); + } } return DynamicInvokeResult.notFound(); }