[GRADLE-2023] Concurrent Modification Exception during 'gradle tasks' Created: 03/Jan/12 Updated: 16/Jan/13 Resolved: 07/Jan/13 |
|
Status: | Resolved |
Project: | Gradle |
Affects Version/s: | 1.0-milestone-6 |
Fix Version/s: | 1.4-rc-1 |
Type: | Bug | ||
Reporter: | Gradle Forums | Assignee: | Luke Daley |
Resolution: | Fixed | Votes: | 13 |
Attachments: | GradleDynamicTaskTest.zip |
Description |
This problem appears in Gradle 1.0 milestone 6. It appears to come from the Cobertura plugin. I've made an effort to identify the origin of the problem, but my build is pretty big and I'm new to Gradle. ========== From my console: =========== [spina:~/Code/apt/StagingGround] spina% gradle tasks --stacktrace ------------------------------------------------------------ FAILURE: Build failed with an exception.
================ END CONSOLE OUTPUT ================= This is my build file: ==== begin build.gradle ==== // The sonar plugin collects build metrics. Useful for quality assurance. sonar { } // This allows all groovy projects to easily reference the same groovy jar for building. //ant.importBuild 'build.xml' allprojects { } subprojects { // The cobertura plugin doesn't come with gradle by default. This makes it available and applies it. sonar { } apply plugin:'java' dependencies { testCompile 'junit:junit:4.4' }test { // Make sure that tests are executed from the APT root. This make relative path lookup work. workingDir = new File(project.projectDir.getCanonicalPath() + "/../") // TODO this is temporary so we can skip tagged tests. systemProperties "apt.build.is.gradle": "true" systemProperties "stsci.skip.performance": "true" // TODO this should be toggled dynamically. systemProperties "stsci.skip.network.tests": "true" }compileJava { // This makes it so that the class filed don't have debug information. // This is how our ant build used to work. options.debug = false }// The ant build puts Manifests into the jar by importing a file. else { logger.info(project.name + " doesn't have a MANIFEST.MF in it's root dir.") }} } If I comment out the following lines then 'gradle tasks' works again: buildscript { I'm not sure how those lines are breaking my build. Note to self, the problem entered my build during the following changeset (found using bisect): The first bad revision is: |
Comments |
Comment by Gradle Forums [ 03/Jan/12 ] |
I got a similar exception when trying to upgrade from milestone-3 to a milestone-7 snapshot. I'm also using the cobertura plugin and will try and see if that is the culprit for me aswell. (i did manage to build my projects but the tasks task bugs out). |
Comment by Szczepan Faber [ 11/Jan/12 ] |
We had a similar problem related to this: http://forums.gradle.org/gradle/topics/upgrading_from_m3_to_m5_causes_a_circular_task_dependency_to_appear If it helps in debugging this problem, I have a feeling that it might be related to existing circular dependency and reasonably complicated multi-project build. |
Comment by Detelin Yordanov [ 30/Jan/12 ] |
Here is a simple build script which demonstrates the issue. I have observed that it happens only on subprojects but not on the root project. |
Comment by Mike M. [ 24/Feb/12 ] |
I can confirm this issue and that it seems to come from the com.orbitz.gradle.cobertura.CoberturaPlugin plugin. We have the error happen only on the root build but not on the individual subprojects (one of our subprojects uses cobertura). When I comment out the cobertura plugin / task config, it works. |
Comment by Warren Muller [ 08/Mar/12 ] |
I have hit this issue creating dynamic tasks in a plugin. The dynamic tasks have dependencies on existing java tasks. The plugin is applied to certain sub-tasks. Interesting is that running 'gradle tasks' fails in the parent project but works in the sub-task where the plugin is applied. |
Comment by Warren Muller [ 08/Mar/12 ] |
i've isolated the line that causes the java.util.ConcurrentModificationException: |
Comment by Warren Muller [ 08/Mar/12 ] |
I've resolved my error by creating a single cleanWsdl task and creating the clean.dependsOn cleanWsdl. The dynamic patter clean<Task> would have all executed the same thing so were redundant when I had more than 1 wsdl anyway. If I had designed it differently with a sourceSet for each wsdl then maybe it would have still occurred but that would be overkill for my purposes. |
Comment by Glen Stampoultzis [ 08/May/12 ] |
I was able to fix this by altering TaskReportTask.java to copy the tasks collection before passing it down to the subprojects. I'm not sure if this is the best way do it though. diff --git a/subprojects/core/src/main/groovy/org/gradle/api/tasks/diagnostics/TaskReportTask.java b/subprojects/core/src/main/groovy/org/gradle/api/tasks/diagnostics/TaskReportTask.java index 8fa2c2c..ee3ce1b 100644 --- a/subprojects/core/src/main/groovy/org/gradle/api/tasks/diagnostics/TaskReportTask.java +++ b/subprojects/core/src/main/groovy/org/gradle/api/tasks/diagnostics/TaskReportTask.java @@ -18,11 +18,13 @@ package org.gradle.api.tasks.diagnostics; import com.google.common.collect.Sets; import org.gradle.api.Project; import org.gradle.api.Rule; +import org.gradle.api.Task; import org.gradle.api.internal.project.ProjectInternal; import org.gradle.api.internal.tasks.CommandLineOption; import org.gradle.api.tasks.diagnostics.internal.*; import java.io.IOException; +import java.util.ArrayList; /** * <p>Displays a list of tasks in the project. An instance of this type is used when you execute the {@code tasks} task @@ -64,7 +66,7 @@ public class TaskReportTask extends AbstractReportTask { for (Project subprojects : project.getSubprojects()) { SingleProjectTaskReportModel subprojectTaskModel = new SingleProjectTaskReportModel(taskDetailsFactory); - subprojectTaskModel.build(subprojects.getTasks()); + subprojectTaskModel.build(new ArrayList<Task>(subprojects.getTasks())); aggregateModel.add(subprojectTaskModel); } |
Comment by Stephane Gallès [ 26/Jun/12 ] |
In gradle 1.0 RC3, same problem when trying to create a task with a dependency on 'uploadArchives' in a plugin |
Comment by Marcin Zajaczkowski [ 09/Jul/12 ] |
I started to have that exception every time with "gradle tasks" after upgrade from 1.0-milestone-9 to 1.0-final. |
Comment by Justin Ryan [ 10/Jul/12 ] |
I ran into this with 1.0 and while I don't know the fix, I have a work around that might help give insight. From a plugin's apply block I was running:
project.clean.dependsOn(':cleanDistribute')
And getting the exception, I changed it to the following to get it working: project.tasks['clean'].dependsOn project.tasks['cleanDistribute'] There's a few things different there, and I don't remember exactly which change made it work. But I believe it was the use of a string in the dependsOn, which is the lazy loading of a depends. Lazy loading and ConcurrentModificationException seems to hang out at the same bars a lot, so I'd bet there's a connection. |
Comment by Stephane Gallès [ 16/Jul/12 ] |
Thanks Justin, your workaround works like a charm. Indeed, I just had to modify the dependsOn parameter in the configuration closure : project.tasks.add('foo') { dependsOn 'uploadArchives' } But this works : project.tasks.add('foo') { dependsOn project.tasks['uploadArchives'] } |
Comment by Thomas Glaeser [ 19/Dec/12 ] |
Still an issue with Gradle 1.3 |
Comment by Thomas Glaeser [ 19/Dec/12 ] |
The workarounds mentioned above probably works in simple scenarious, but when applying a plugin that makes usage of task rules there is no way to control this from the script. |
Comment by René Gröschke (Inactive) [ 20/Dec/12 ] |
This is not caused by adding simple task actions during execution phase as I expected. I think its a problem on how we deal with task rules. |
Comment by Michael Brand [ 16/Jan/13 ] |
Is this issue resolved? I'm seeing something similar using task rules, but I'm still on version 1.2. Does anyone know of a workaround for task rules that doesn't involve updating Gradle versions? |
Comment by Thomas Glaeser [ 16/Jan/13 ] |
This is fixed in upcoming Gradle 1.4. Meanwhile you might try the following workaround (should be configured in the root project): allprojects { it.implicitTasks.matching { it.name == "tasks" }.all { doFirst { rootProject.allprojects.each { def seen = new HashSet() while (seen != it.tasks) { new HashSet(it.tasks).each { it.getTaskDependencies().getDependencies(it) seen << it } } } } } } |
Comment by Michael Brand [ 16/Jan/13 ] |
That worked! Thanks for the quick response. |