Provide better error message when trying to add a task action from a task action


(spencer_allain) #1
task blowsUp << {
doFirst { println 'ConcurrentModificationException' } }

I basically never use the short-cut form, but in building up some internal training materials I attempted to do the above essentially to see what would happen, and wasn’t quite expecting the below exception.

The exception logically makes sense as the actions list is indeed being modified while being iterated over, but it seems that the only way that should be possible is by nesting doFirst and/or doLast closures. I rather would have expected gradle to spit out a message something to the effect that nested doFirst/doLast closure blocks are disallowed.

The other possible option would be to change the internal list structure explicitly to use a CopyOnWriteArrayList so that changes after iteration has started would simply not be seen. That would mask issues though, so failing early seems like a much better option, just ideally with a nicer message to the user.

Below is the actual exception that occurs using 1.0-milestone-9:

java.util.ConcurrentModificationException

at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)

at java.util.AbstractList$Itr.next(AbstractList.java:343)

at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:56)

at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:46)

at org.gradle.api.internal.tasks.execution.PostExecutionAnalysisTaskExecuter.execute(PostExecutionAnalysisTaskExecuter.java:34)

at org.gradle.api.internal.changedetection.CacheLockHandlingTaskExecuter$1.run(CacheLockHandlingTaskExecuter.java:34)

at org.gradle.cache.internal.DefaultCacheAccess$2.create(DefaultCacheAccess.java:200)

at org.gradle.cache.internal.DefaultCacheAccess.longRunningOperation(DefaultCacheAccess.java:172)

at org.gradle.cache.internal.DefaultCacheAccess.longRunningOperation(DefaultCacheAccess.java:198)

at org.gradle.cache.internal.DefaultPersistentDirectoryStore.longRunningOperation(DefaultPersistentDirectoryStore.java:111)

at org.gradle.api.internal.changedetection.DefaultTaskArtifactStateCacheAccess.longRunningOperation(DefaultTaskArtifactStateCacheAccess.java:83)

at org.gradle.api.internal.changedetection.CacheLockHandlingTaskExecuter.execute(CacheLockHandlingTaskExecuter.java:32)

at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:55)

at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:57)

at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:41)

at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:51)

at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:52)

at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:42)

at org.gradle.api.internal.AbstractTask.executeWithoutThrowingTaskFailure(AbstractTask.java:247)

at org.gradle.execution.DefaultTaskGraphExecuter.executeTask(DefaultTaskGraphExecuter.java:192)

at org.gradle.execution.DefaultTaskGraphExecuter.doExecute(DefaultTaskGraphExecuter.java:177)

at org.gradle.execution.DefaultTaskGraphExecuter.execute(DefaultTaskGraphExecuter.java:83)

at org.gradle.execution.SelectedTaskExecutionAction.execute(SelectedTaskExecutionAction.java:36)

at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:61)

at org.gradle.execution.DefaultBuildExecuter.access$200(DefaultBuildExecuter.java:23)

at org.gradle.execution.DefaultBuildExecuter$2.proceed(DefaultBuildExecuter.java:67)

at org.gradle.api.internal.changedetection.TaskCacheLockHandlingBuildExecuter$1.run(TaskCacheLockHandlingBuildExecuter.java:31)

at org.gradle.cache.internal.DefaultCacheAccess$1.create(DefaultCacheAccess.java:111)

at org.gradle.cache.internal.DefaultCacheAccess.useCache(DefaultCacheAccess.java:126)

at org.gradle.cache.internal.DefaultCacheAccess.useCache(DefaultCacheAccess.java:109)

at org.gradle.cache.internal.DefaultPersistentDirectoryStore.useCache(DefaultPersistentDirectoryStore.java:103)

at org.gradle.api.internal.changedetection.DefaultTaskArtifactStateCacheAccess.useCache(DefaultTaskArtifactStateCacheAccess.java:79)

at org.gradle.api.internal.changedetection.TaskCacheLockHandlingBuildExecuter.execute(TaskCacheLockHandlingBuildExecuter.java:29)

at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:61)

at org.gradle.execution.DefaultBuildExecuter.access$200(DefaultBuildExecuter.java:23)

at org.gradle.execution.DefaultBuildExecuter$2.proceed(DefaultBuildExecuter.java:67)

at org.gradle.execution.DryRunBuildExecutionAction.execute(DryRunBuildExecutionAction.java:32)

at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:61)

at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:54)

at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:155)

at org.gradle.initialization.DefaultGradleLauncher.doBuild(DefaultGradleLauncher.java:110)

at org.gradle.initialization.DefaultGradleLauncher.run(DefaultGradleLauncher.java:78)

at org.gradle.launcher.cli.RunBuildAction.execute(RunBuildAction.java:42)

at org.gradle.launcher.cli.RunBuildAction.execute(RunBuildAction.java:28)

at org.gradle.launcher.exec.ExceptionReportingAction.execute(ExceptionReportingAction.java:32)

at org.gradle.launcher.exec.ExceptionReportingAction.execute(ExceptionReportingAction.java:21)

at org.gradle.launcher.cli.CommandLineActionFactory$WithLoggingAction.execute(CommandLineActionFactory.java:302)

at org.gradle.launcher.cli.CommandLineActionFactory$WithLoggingAction.execute(CommandLineActionFactory.java:286)

at org.gradle.launcher.Main.doAction(Main.java:48)

at org.gradle.launcher.exec.EntryPoint$1.execute(EntryPoint.java:53)

at org.gradle.launcher.exec.EntryPoint$1.execute(EntryPoint.java:51)

at org.gradle.launcher.exec.Execution.execute(Execution.java:28)

at org.gradle.launcher.exec.EntryPoint.run(EntryPoint.java:39)

at org.gradle.launcher.Main.main(Main.java:39)

at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)

at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)

at java.lang.reflect.Method.invoke(Method.java:597)

at org.gradle.launcher.ProcessBootstrap.runNoExit(ProcessBootstrap.java:51)

at org.gradle.launcher.ProcessBootstrap.run(ProcessBootstrap.java:33)

at org.gradle.launcher.GradleMain.main(GradleMain.java:24)

-Spencer


(Luke Daley) #2

I’ve reworded the title, converted this to an idea and exported to JIRA as GRADLE-2219.

Thanks Spencer.