I have the following setup in my project:
-
A plugin (let’s call it “A”), which serves the following purposes:
- This plugin can be applied to any project
- During the application of plugin “A”, this plugin finds the root project and applies plugin “B” to the root project
- Plugin “A” also configures various test tasks of the current project
-
Plugin “B”, which plays the following role:
- During application, this plugin creates an instance of a “Configuration” object
- In the configuration object, it defines a dependency on a single JAR, which is located in the local Maven repository
- It registers a shared build service, to which it passes the previously created configuration via parameters
-
A “shared build service”, which is responsible for:
- Downloading the required JAR from the local Maven repository
- Starting a local test Elasticsearch node (requires the JAR from the previous step)
- To download the dependent JAR, I absolutely want to use Gradle’s mechanisms and API, i.e., the configuration object and the resolution of dependencies defined in it
Whichever implementation method I use, I always struggle with an error like:
“Resolution of the configuration ‘:elasticsearchApp’ was attempted without an exclusive lock. This is unsafe and not allowed”
I have tried the following approaches:
- Configuration provider
Key code snippets from plugin “B”:
Provider<Configuration> elasticsearchAppProvider = project.getConfigurations().register("elasticsearchApp", conf -> {
conf.setCanBeResolved(true);
conf.setCanBeConsumed(false);
conf.withDependencies(deps -> deps.add(
project.getDependencies().create("com.xxx.p7:p7-local-elasticsearch:" + version)
));
});
Provider<Set<File>> artifacts = elasticsearchAppProvider.map(conf -> conf.getIncoming().getFiles().getFiles());
project.getGradle()
.getSharedServices()
.registerIfAbsent("elasticsearchApp", ElasticsearchTestingInstance.class, spec -> {
spec.getParameters().getClasspath().set(artifacts);
spec.getParameters().getAddressFile().set(new File(project.getRootDir(), ".esAddress"));
});
Result: “Resolution of the configuration ‘:elasticsearchApp’ was attempted without an exclusive lock. This is unsafe and not allowed.”
- Detached configuration
Key code snippets from plugin “B”:
Configuration elasticsearchApp = project.getConfigurations().detachedConfiguration(
project.getDependencies().create("com.xxx.p7:p7-local-elasticsearch:" + version)
);
project.getGradle()
.getSharedServices()
.registerIfAbsent("elasticsearchApp", ElasticsearchTestingInstance.class, spec -> {
spec.getParameters().getClasspath().set(elasticsearchApp.getIncoming().getFiles().getFiles());
spec.getParameters().getAddressFile().set(new File(project.getRootDir(), ".esAddress"));
});
Result: “Resolution of the configuration ‘:detachedConfiguration1’ was attempted without an exclusive lock. This is unsafe and not allowed”
- Detached configuration with immediate resolution
Key code snippets from plugin “B”:
Configuration elasticsearchApp = project.getConfigurations().detachedConfiguration(
project.getDependencies().create("com.xxx.p7:p7-local-elasticsearch:" + version)
);
Set<File> artifacts = elasticsearchApp.getIncoming().getFiles().getFiles();
project.getGradle()
.getSharedServices()
.registerIfAbsent("elasticsearchApp", ElasticsearchTestingInstance.class, spec -> {
spec.getParameters().getClasspath().set(artifacts);
spec.getParameters().getAddressFile().set(new File(project.getRootDir(), ".esAddress"));
});
Result: “Resolution of the configuration ‘:detachedConfiguration1’ was attempted without an exclusive lock. This is unsafe and not allowed.”
Question
What is the recommended approach in this case? What API should I use to get rid of the “Resolution of the configuration…” error when using a configuration in the context of a shared build service?