Skip to content

Commit

Permalink
Realize jvm toolchain repositories when marked immutable
Browse files Browse the repository at this point in the history
Fixes #24669
  • Loading branch information
ljacomet committed Apr 7, 2023
1 parent f6125cb commit 770eee5
Show file tree
Hide file tree
Showing 6 changed files with 280 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class JavaToolchainDownloadSpiIntegrationTest extends AbstractJavaToolchainDownl
@ToBeFixedForConfigurationCache(because = "Fails the build with an additional error")
def "can inject custom toolchain registry via settings plugin"() {
settingsFile << """
${applyToolchainResolverPlugin("CustomToolchainResolver", customToolchainResolverCode())}
${applyToolchainResolverPlugin("CustomToolchainResolver", customToolchainResolverCode())}
toolchainManagement {
jvm {
javaRepositories {
Expand Down Expand Up @@ -68,7 +68,7 @@ class JavaToolchainDownloadSpiIntegrationTest extends AbstractJavaToolchainDownl
@ToBeFixedForConfigurationCache(because = "Fails the build with an additional error")
def "downloaded JDK is checked against the spec"() {
settingsFile << """
${applyToolchainResolverPlugin("BrokenToolchainResolver", brokenToolchainResolverCode())}
${applyToolchainResolverPlugin("BrokenToolchainResolver", brokenToolchainResolverCode())}
toolchainManagement {
jvm {
javaRepositories {
Expand Down Expand Up @@ -111,7 +111,7 @@ class JavaToolchainDownloadSpiIntegrationTest extends AbstractJavaToolchainDownl
def "custom toolchain registries are consulted in order"() {
settingsFile << """
${applyToolchainResolverPlugin("CustomToolchainResolver", customToolchainResolverCode())}
${applyToolchainResolverPlugin("UselessToolchainResolver", uselessToolchainResolverCode("UselessToolchainResolver"))}
${applyToolchainResolverPlugin("UselessToolchainResolver", uselessToolchainResolverCode("UselessToolchainResolver"))}
toolchainManagement {
jvm {
javaRepositories {
Expand Down Expand Up @@ -197,7 +197,7 @@ class JavaToolchainDownloadSpiIntegrationTest extends AbstractJavaToolchainDownl

def "fails on implementation class collision"() {
settingsFile << """
${applyToolchainResolverPlugin("UselessToolchainResolver", uselessToolchainResolverCode("UselessToolchainResolver"))}
${applyToolchainResolverPlugin("UselessToolchainResolver", uselessToolchainResolverCode("UselessToolchainResolver"))}
toolchainManagement {
jvm {
javaRepositories {
Expand Down Expand Up @@ -232,13 +232,13 @@ class JavaToolchainDownloadSpiIntegrationTest extends AbstractJavaToolchainDownl
.runWithFailure()

then:
failure.assertHasCause("Duplicate configuration for repository implementation 'UselessToolchainResolver'.")
failure.assertHasDescription("Duplicate configuration for repository implementation 'UselessToolchainResolver'.")
}

def "fails on repository name collision"() {
settingsFile << """
${applyToolchainResolverPlugin("UselessToolchainResolver1", uselessToolchainResolverCode("UselessToolchainResolver1"))}
${applyToolchainResolverPlugin("UselessToolchainResolver2", uselessToolchainResolverCode("UselessToolchainResolver2"))}
${applyToolchainResolverPlugin("UselessToolchainResolver1", uselessToolchainResolverCode("UselessToolchainResolver1"))}
${applyToolchainResolverPlugin("UselessToolchainResolver2", uselessToolchainResolverCode("UselessToolchainResolver2"))}
toolchainManagement {
jvm {
javaRepositories {
Expand Down Expand Up @@ -278,9 +278,9 @@ class JavaToolchainDownloadSpiIntegrationTest extends AbstractJavaToolchainDownl

def "list of requested repositories can be queried"() {
settingsFile << """
${applyToolchainResolverPlugin("UselessToolchainResolver1", uselessToolchainResolverCode("UselessToolchainResolver1"))}
${applyToolchainResolverPlugin("UselessToolchainResolver2", uselessToolchainResolverCode("UselessToolchainResolver2"))}
${applyToolchainResolverPlugin("UselessToolchainResolver3", uselessToolchainResolverCode("UselessToolchainResolver3"))}
${applyToolchainResolverPlugin("UselessToolchainResolver1", uselessToolchainResolverCode("UselessToolchainResolver1"))}
${applyToolchainResolverPlugin("UselessToolchainResolver2", uselessToolchainResolverCode("UselessToolchainResolver2"))}
${applyToolchainResolverPlugin("UselessToolchainResolver3", uselessToolchainResolverCode("UselessToolchainResolver3"))}
toolchainManagement {
jvm {
javaRepositories {
Expand All @@ -293,7 +293,7 @@ class JavaToolchainDownloadSpiIntegrationTest extends AbstractJavaToolchainDownl
}
}
}
println(\"\"\"Explicitly requested toolchains: \${toolchainManagement.jvm.getJavaRepositories().getAsList().collect { it.getName() }}.\"\"\")
"""

Expand Down Expand Up @@ -322,9 +322,9 @@ class JavaToolchainDownloadSpiIntegrationTest extends AbstractJavaToolchainDownl

def "created repository can be removed"() {
settingsFile << """
${applyToolchainResolverPlugin("UselessToolchainResolver1", uselessToolchainResolverCode("UselessToolchainResolver1"))}
${applyToolchainResolverPlugin("UselessToolchainResolver2", uselessToolchainResolverCode("UselessToolchainResolver2"))}
${applyToolchainResolverPlugin("UselessToolchainResolver3", uselessToolchainResolverCode("UselessToolchainResolver3"))}
${applyToolchainResolverPlugin("UselessToolchainResolver1", uselessToolchainResolverCode("UselessToolchainResolver1"))}
${applyToolchainResolverPlugin("UselessToolchainResolver2", uselessToolchainResolverCode("UselessToolchainResolver2"))}
${applyToolchainResolverPlugin("UselessToolchainResolver3", uselessToolchainResolverCode("UselessToolchainResolver3"))}
toolchainManagement {
jvm {
javaRepositories {
Expand All @@ -340,9 +340,9 @@ class JavaToolchainDownloadSpiIntegrationTest extends AbstractJavaToolchainDownl
}
}
}
toolchainManagement.jvm.javaRepositories.remove('useless2')
println(\"\"\"Explicitly requested toolchains: \${toolchainManagement.jvm.getJavaRepositories().getAsList().collect { it.getName() }}.\"\"\")
"""

Expand Down Expand Up @@ -371,7 +371,7 @@ class JavaToolchainDownloadSpiIntegrationTest extends AbstractJavaToolchainDownl

def "cannot mutate repository rules after settings have been evaluated"() {
settingsFile << """
${applyToolchainResolverPlugin("UselessToolchainResolver", uselessToolchainResolverCode("UselessToolchainResolver"))}
${applyToolchainResolverPlugin("UselessToolchainResolver", uselessToolchainResolverCode("UselessToolchainResolver"))}
toolchainManagement {
jvm {
javaRepositories {
Expand All @@ -397,7 +397,7 @@ class JavaToolchainDownloadSpiIntegrationTest extends AbstractJavaToolchainDownl
@ToBeFixedForConfigurationCache(because = "Fails the build with an additional error")
def "throws informative error on repositories not being configured"() {
settingsFile << """
${applyToolchainResolverPlugin("CustomToolchainResolver", customToolchainResolverCode())}
${applyToolchainResolverPlugin("CustomToolchainResolver", customToolchainResolverCode())}
"""

buildFile << """
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ public List<RealizedJavaToolchainRepository> requestedRepositories() {
@Override
public void preventFromFurtherMutation() {
repositoryHandler.preventFromFurtherMutation();
// This makes sure all configured elements have been transformed in their internal representation for later use
realizeRepositories();
}

private void realizeRepositories() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright 2020 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.integtests.tooling.r81;

import org.gradle.tooling.BuildAction;
import org.gradle.tooling.BuildController;
import org.gradle.tooling.model.gradle.BasicGradleProject;
import org.gradle.tooling.model.gradle.GradleBuild;

import java.util.ArrayList;
import java.util.List;

public class ActionRunsNestedActions implements BuildAction<Models> {
@Override
public Models execute(BuildController controller) {
GradleBuild buildModel = controller.getBuildModel();
List<GetProjectModel> projectActions = new ArrayList<GetProjectModel>();
for (BasicGradleProject project : buildModel.getProjects()) {
projectActions.add(new GetProjectModel(project));
}
List<ToolchainModel> results = controller.run(projectActions);
return new Models(controller.getCanQueryProjectModelInParallel(ToolchainModel.class), results);
}

static class GetProjectModel implements BuildAction<ToolchainModel> {
private final BasicGradleProject project;

public GetProjectModel(BasicGradleProject project) {
this.project = project;
}

@Override
public ToolchainModel execute(BuildController controller) {
return controller.getModel(project, ToolchainModel.class);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright 2020 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.integtests.tooling.r81;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class Models implements Serializable {
private final boolean runsInParallel;
private final List<ToolchainModel> projects;

public Models(boolean runsInParallel, Collection<ToolchainModel> projects) {
this.runsInParallel = runsInParallel;
this.projects = new ArrayList<ToolchainModel>(projects);
}

public boolean isMayRunInParallel() {
return runsInParallel;
}

public List<ToolchainModel> getProjects() {
return projects;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright 2023 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.integtests.tooling.r81;

public interface ToolchainModel {

String getPath();

int getJavaVersion();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
/*
* Copyright 2023 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.integtests.tooling.r81

import org.gradle.integtests.tooling.fixture.TargetGradleVersion
import org.gradle.integtests.tooling.fixture.ToolingApiSpecification
import org.gradle.integtests.tooling.fixture.ToolingApiVersion
import org.gradle.tooling.BuildActionFailureException

@ToolingApiVersion(">=8.1")
class ToolchainsParallelActionExecutionCrossVersionSpec extends ToolingApiSpecification {

def setup() {
buildFile << """
import javax.inject.Inject
import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry
import org.gradle.tooling.provider.model.ToolingModelBuilder
class ToolchainPlugin implements Plugin<Project> {
ToolingModelBuilderRegistry registry
@Inject
ToolchainPlugin(ToolingModelBuilderRegistry registry) {
this.registry = registry
}
void apply(Project project) {
registry.register(new ToolchainBuilder())
}
}
class ToolchainModel implements Serializable {
String path
Integer javaVersion
}
class ToolchainBuilder implements ToolingModelBuilder {
boolean canBuild(String modelName) {
return modelName == "org.gradle.integtests.tooling.r81.ToolchainModel"
}
Object buildAll(String modelName, Project project) {
// Access toolchain related information
def compileJavaVersion = project.tasks.compileJava.javaCompiler.get().metadata.languageVersion.asInt()
return new ToolchainModel(path: project.path, javaVersion: compileJavaVersion);
}
}
"""
}

@TargetGradleVersion(">=8.1")
def "nested actions that query a project model which leverages toolchain information do not cause Property evaluation to be in unexpected state"() {
given:
setupBuildWithToolchainsResolution()

when:
withConnection {
def action = action(new ActionRunsNestedActions())
action.standardOutput = System.out
action.standardError = System.err
action.addArguments("--parallel")
action.run()
}

then:
def e = thrown(BuildActionFailureException)
def root = rootCause(e)
root.message.startsWith('No locally installed toolchains match')
}

def rootCause(Exception e) {
def ex = e
while (ex.cause != null) {
ex = ex.cause
}
ex
}

def setupBuildWithToolchainsResolution() {
settingsFile << """
import java.util.Optional;
import org.gradle.platform.BuildPlatform;
public abstract class FakeResolver implements JavaToolchainResolver {
@Override
public Optional<JavaToolchainDownload> resolve(JavaToolchainRequest request) {
return Optional.empty();
}
}
public abstract class FakeProvider implements Plugin<Settings> {
@Inject
protected abstract JavaToolchainResolverRegistry getToolchainResolverRegistry();
void apply(Settings settings) {
settings.getPlugins().apply("jvm-toolchain-management");
JavaToolchainResolverRegistry registry = getToolchainResolverRegistry();
registry.register(FakeResolver.class);
}
}
apply plugin: FakeProvider
toolchainManagement {
jvm {
javaRepositories {
repository('useless') {
resolverClass = FakeResolver
}
}
}
}
rootProject.name = 'root'
include 'a', 'b'
"""
buildFile << """
allprojects {
apply plugin: ToolchainPlugin
apply plugin: 'java'
java {
toolchain {
// Using a toolchain that triggers auto-provisioning is needed
languageVersion = JavaLanguageVersion.of('99')
}
}
}
"""
}
}

0 comments on commit 770eee5

Please sign in to comment.