New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gradle Plugin for JaCoCo can't handle filenames containing '$$' in path #433

Closed
Egorand opened this Issue Jul 18, 2016 · 13 comments

Comments

Projects
None yet
3 participants
@Egorand

Egorand commented Jul 18, 2016

Steps to reproduce

JaCoCo version: 0.7.7.201606060606
Operating system: OS X 10.11.5
Tool integration: Gradle

Run JaCoCo code coverage using the Gradle plugin on an Android project, written entirely in Kotlin.

Expected behaviour

Code coverage task runs successfully.

Actual behaviour

Code coverage task fails with the following stack trace:

org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':app:testDebugUnitTestCoverage'.
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:69)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:46)
        at org.gradle.api.internal.tasks.execution.PostExecutionAnalysisTaskExecuter.execute(PostExecutionAnalysisTaskExecuter.java:35)
        at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:66)
        at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:58)
        at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:52)
        at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:52)
        at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:53)
        at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:43)
        at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:203)
        at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:185)
        at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.processTask(AbstractTaskPlanExecutor.java:66)
        at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.run(AbstractTaskPlanExecutor.java:50)
        at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor.process(DefaultTaskPlanExecutor.java:25)
        at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter.execute(DefaultTaskGraphExecuter.java:110)
        at org.gradle.execution.SelectedTaskExecutionAction.execute(SelectedTaskExecutionAction.java:37)
        at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:37)
        at org.gradle.execution.DefaultBuildExecuter.access$000(DefaultBuildExecuter.java:23)
        at org.gradle.execution.DefaultBuildExecuter$1.proceed(DefaultBuildExecuter.java:43)
        at org.gradle.execution.DryRunBuildExecutionAction.execute(DryRunBuildExecutionAction.java:32)
        at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:37)
        at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:30)
        at org.gradle.initialization.DefaultGradleLauncher$4.run(DefaultGradleLauncher.java:153)
        at org.gradle.internal.Factories$1.create(Factories.java:22)
        at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:91)
        at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:53)
        at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:150)
        at org.gradle.initialization.DefaultGradleLauncher.access$200(DefaultGradleLauncher.java:32)
        at org.gradle.initialization.DefaultGradleLauncher$1.create(DefaultGradleLauncher.java:98)
        at org.gradle.initialization.DefaultGradleLauncher$1.create(DefaultGradleLauncher.java:92)
        at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:91)
        at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:63)
        at org.gradle.initialization.DefaultGradleLauncher.doBuild(DefaultGradleLauncher.java:92)
        at org.gradle.initialization.DefaultGradleLauncher.run(DefaultGradleLauncher.java:83)
        at org.gradle.launcher.exec.InProcessBuildActionExecuter$DefaultBuildController.run(InProcessBuildActionExecuter.java:99)
        at org.gradle.tooling.internal.provider.ExecuteBuildActionRunner.run(ExecuteBuildActionRunner.java:28)
        at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35)
        at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:48)
        at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:30)
        at org.gradle.launcher.exec.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:81)
        at org.gradle.launcher.exec.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:46)
        at org.gradle.launcher.daemon.server.exec.ExecuteBuild.doBuild(ExecuteBuild.java:52)
        at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
        at org.gradle.launcher.daemon.server.exec.WatchForDisconnection.execute(WatchForDisconnection.java:37)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
        at org.gradle.launcher.daemon.server.exec.ResetDeprecationLogger.execute(ResetDeprecationLogger.java:26)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
        at org.gradle.launcher.daemon.server.exec.RequestStopIfSingleUsedDaemon.execute(RequestStopIfSingleUsedDaemon.java:34)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
        at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.call(ForwardClientInput.java:74)
        at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.call(ForwardClientInput.java:72)
        at org.gradle.util.Swapper.swap(Swapper.java:38)
        at org.gradle.launcher.daemon.server.exec.ForwardClientInput.execute(ForwardClientInput.java:72)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
        at org.gradle.launcher.daemon.server.health.DaemonHealthTracker.execute(DaemonHealthTracker.java:47)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
        at org.gradle.launcher.daemon.server.exec.LogToClient.doBuild(LogToClient.java:60)
        at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
        at org.gradle.launcher.daemon.server.exec.EstablishBuildEnvironment.doBuild(EstablishBuildEnvironment.java:72)
        at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
        at org.gradle.launcher.daemon.server.health.HintGCAfterBuild.execute(HintGCAfterBuild.java:41)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
        at org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy$1.run(StartBuildOrRespondWithBusy.java:50)
        at org.gradle.launcher.daemon.server.DaemonStateCoordinator$1.run(DaemonStateCoordinator.java:237)
        at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:54)
        at org.gradle.internal.concurrent.StoppableExecutorImpl$1.run(StoppableExecutorImpl.java:40)
Caused by: : Error while creating report
        at org.jacoco.ant.ReportTask.execute(ReportTask.java:501)
        at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:293)
        at org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:106)
        at org.gradle.api.internal.project.ant.BasicAntBuilder.nodeCompleted(BasicAntBuilder.java:78)
        at org.gradle.internal.metaobject.BeanDynamicObject$MetaClassAdapter.invokeMethod(BeanDynamicObject.java:374)
        at org.gradle.internal.metaobject.BeanDynamicObject.invokeMethod(BeanDynamicObject.java:169)
        at org.gradle.internal.metaobject.AbstractDynamicObject.invokeMethod(AbstractDynamicObject.java:163)
        at org.gradle.api.internal.project.antbuilder.AntBuilderDelegate.nodeCompleted(AntBuilderDelegate.java:118)
        at org.gradle.internal.jacoco.AntJacocoReport$1.doCall(AntJacocoReport.java:50)
        at org.gradle.api.internal.ClosureBackedAction.execute(ClosureBackedAction.java:67)
        at org.gradle.api.internal.project.antbuilder.DefaultIsolatedAntBuilder$2.execute(DefaultIsolatedAntBuilder.java:162)
        at org.gradle.api.internal.project.antbuilder.DefaultIsolatedAntBuilder$2.execute(DefaultIsolatedAntBuilder.java:144)
        at org.gradle.api.internal.project.antbuilder.ClassPathToClassLoaderCache.withCachedClassLoader(ClassPathToClassLoaderCache.java:134)
        at org.gradle.api.internal.project.antbuilder.DefaultIsolatedAntBuilder.execute(DefaultIsolatedAntBuilder.java:138)
        at org.gradle.internal.jacoco.AntJacocoReport.execute(AntJacocoReport.java:41)
        at org.gradle.testing.jacoco.tasks.JacocoReport.generate(JacocoReport.java:174)
        at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:75)
        at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.doExecute(AnnotationProcessingTaskFactory.java:228)
        at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.execute(AnnotationProcessingTaskFactory.java:221)
        at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.execute(AnnotationProcessingTaskFactory.java:210)
        at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:621)
        at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:604)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:80)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:61)
        ... 68 more
Caused by: java.io.FileNotFoundException: /<project-dir>/app/build/intermediates/classes/debug/me/egorand/gigmate/ui/fragment/ArtistSearchFragment$renderArtists$inlined$onUiThread$1.class (No such file or directory)
        at org.apache.tools.ant.types.resources.FileResource.getInputStream(FileResource.java:217)
        at org.jacoco.ant.ReportTask.createBundle(ReportTask.java:569)
        at org.jacoco.ant.ReportTask.createReport(ReportTask.java:542)
        at org.jacoco.ant.ReportTask.execute(ReportTask.java:495)
        ... 91 more

When I navigate to the classes directory I see that the class file that JaCoCo can't locate has a different name:

ArtistSearchFragment$renderArtists$$inlined$onUiThread$1.class

Notice the double dollar sign before inlined, which may be the cause of the problem.

@marchof

This comment has been minimized.

Show comment
Hide comment
@marchof

marchof Jul 19, 2016

Member

@Godin I think we have seen the $$-issue before with Android projects. Can you remember? Wasn't this some DEX/Dalvic issue?

Member

marchof commented Jul 19, 2016

@Godin I think we have seen the $$-issue before with Android projects. Can you remember? Wasn't this some DEX/Dalvic issue?

@Godin

This comment has been minimized.

Show comment
Hide comment
@Godin

Godin Jul 19, 2016

Member

@marchof I don't remember discussion in context of Android project, but I remember discussion about dollars in class names in context of issue #383 , which was about lambdas and OpenJDK version. Also I have strong feeling that here it relates to Kotlin...

@Egorand could you please provide minimalistic example/reproducer demonstrating this issue? and specify JDK version which you use.

Member

Godin commented Jul 19, 2016

@marchof I don't remember discussion in context of Android project, but I remember discussion about dollars in class names in context of issue #383 , which was about lambdas and OpenJDK version. Also I have strong feeling that here it relates to Kotlin...

@Egorand could you please provide minimalistic example/reproducer demonstrating this issue? and specify JDK version which you use.

@Egorand

This comment has been minimized.

Show comment
Hide comment
@Egorand

Egorand Jul 19, 2016

@Godin Sure, I can publish a small Android app closer to or during the weekend. As the stacktrace shows, I bumped into the problem when using anko's onUiThread() function, but I could also reproduce it with Kotlin's with statement.

Egorand commented Jul 19, 2016

@Godin Sure, I can publish a small Android app closer to or during the weekend. As the stacktrace shows, I bumped into the problem when using anko's onUiThread() function, but I could also reproduce it with Kotlin's with statement.

@Egorand

This comment has been minimized.

Show comment
Hide comment
@Egorand

Egorand Jul 19, 2016

Btw, I totally forgot to link the issue I opened in Kotlin's issue tracker, where it got rejected: KT-13131 JaCoCo: FileNotFoundException when processing $$inlined

Egorand commented Jul 19, 2016

Btw, I totally forgot to link the issue I opened in Kotlin's issue tracker, where it got rejected: KT-13131 JaCoCo: FileNotFoundException when processing $$inlined

@Godin

This comment has been minimized.

Show comment
Hide comment
@Godin

Godin Jul 20, 2016

Member

For the next code ( mostly the same as file from tests for Kotlin compiler ) Kotlin produces class file with $$inlined in name:

class HelloWorld {
    public fun getMessage(bigger : Boolean) : String {
        var encl = "fail";
        test {
            {
                encl = "Hello World!"
            }()
        }
        return encl
    }

    inline fun test(crossinline s: () -> Unit) {
        s()
    }
}

And our Maven Plugin and Ant Tasks works just fine with it.

And taking into account messages in internet ( e.g. http://stackoverflow.com/a/29124012/244993 ) problem is definitely not in Kotlin and most likely not in JaCoCo, but somewhere else, e.g. in Gradle Plugin.

@Egorand from here if you can provide a reproducer, then I can have a look and try to find root cause, but fix most likely won't depend on us.

Member

Godin commented Jul 20, 2016

For the next code ( mostly the same as file from tests for Kotlin compiler ) Kotlin produces class file with $$inlined in name:

class HelloWorld {
    public fun getMessage(bigger : Boolean) : String {
        var encl = "fail";
        test {
            {
                encl = "Hello World!"
            }()
        }
        return encl
    }

    inline fun test(crossinline s: () -> Unit) {
        s()
    }
}

And our Maven Plugin and Ant Tasks works just fine with it.

And taking into account messages in internet ( e.g. http://stackoverflow.com/a/29124012/244993 ) problem is definitely not in Kotlin and most likely not in JaCoCo, but somewhere else, e.g. in Gradle Plugin.

@Egorand from here if you can provide a reproducer, then I can have a look and try to find root cause, but fix most likely won't depend on us.

@Egorand

This comment has been minimized.

Show comment
Hide comment
@Egorand

Egorand Jul 23, 2016

@Godin I've published a small Android project that reproduces the issue, it's here. StringPrinterFragment uses anko's runOnUiThread() function, which is implemented using both inline and crossinline statements. It might happen that one of those causes the error. Please let me know if you need any additional info.

Egorand commented Jul 23, 2016

@Godin I've published a small Android project that reproduces the issue, it's here. StringPrinterFragment uses anko's runOnUiThread() function, which is implemented using both inline and crossinline statements. It might happen that one of those causes the error. Please let me know if you need any additional info.

@Godin

This comment has been minimized.

Show comment
Hide comment
@Godin

Godin Jul 24, 2016

Member

@Egorand Gradle JaCoCo Plugin wraps and executes JaCoCo Ant Task for generation or report. I updated your example to invoke JaCoCo Ant Task directly bypassing Gradle JaCoCo Plugin - https://github.com/Godin/gradle-jacoco-issue/tree/use-jacoco-ant-task and this works, hence the root of the problem definitely lies somewhere inside of a Gradle.

My best guess - is that Gradle JaCoCo Plugin tries to pass list of files ( https://github.com/gradle/gradle/blob/bd16679a8402ba0568454d2d144c32f4d0a15d4d/subprojects/jacoco/src/main/java/org/gradle/internal/jacoco/AntJacocoReport.java#L63 ) and $$ in path of files is not escaped, so that interpreted by Ant as a single $ - see https://ant.apache.org/manual/properties.html

Not sure that in a short term I'll have time to dig deeper.

Member

Godin commented Jul 24, 2016

@Egorand Gradle JaCoCo Plugin wraps and executes JaCoCo Ant Task for generation or report. I updated your example to invoke JaCoCo Ant Task directly bypassing Gradle JaCoCo Plugin - https://github.com/Godin/gradle-jacoco-issue/tree/use-jacoco-ant-task and this works, hence the root of the problem definitely lies somewhere inside of a Gradle.

My best guess - is that Gradle JaCoCo Plugin tries to pass list of files ( https://github.com/gradle/gradle/blob/bd16679a8402ba0568454d2d144c32f4d0a15d4d/subprojects/jacoco/src/main/java/org/gradle/internal/jacoco/AntJacocoReport.java#L63 ) and $$ in path of files is not escaped, so that interpreted by Ant as a single $ - see https://ant.apache.org/manual/properties.html

Not sure that in a short term I'll have time to dig deeper.

@Egorand

This comment has been minimized.

Show comment
Hide comment
@Egorand

Egorand Jul 24, 2016

Thanks a lot for the insight @Godin! Will it make sense to report this to the Gradle team?

Egorand commented Jul 24, 2016

Thanks a lot for the insight @Godin! Will it make sense to report this to the Gradle team?

@Godin

This comment has been minimized.

Show comment
Hide comment
@Godin

Godin Jul 25, 2016

Member

@Egorand it will be great if you will help us to report this to Gradle 👍 actually not only JaCoCo might be affected. Keep us posted. Thanks!

Member

Godin commented Jul 25, 2016

@Egorand it will be great if you will help us to report this to Gradle 👍 actually not only JaCoCo might be affected. Keep us posted. Thanks!

@Egorand

This comment has been minimized.

Show comment
Hide comment
@Egorand

Egorand commented Jul 26, 2016

I reported the issue: https://discuss.gradle.org/t/java-io-filenotfoundexception-when-running-jacoco-inside-an-android-kotin-project/18675, and they have opened a JIRA ticket already.

There's already a commit on this issue, might be interesting for you: https://code-review.gradle.org/changelog/Gradle?cs=b6503cb2462ab84ce65ae51761eec49efd3160ae

@Godin Godin changed the title from java.io.FileNotFoundException inside a Android Kotlin project to Gradle Plugin for JaCoCo can't handle filenames containing '$$' in path Jul 26, 2016

@Godin

This comment has been minimized.

Show comment
Hide comment
@Godin

Godin Jul 26, 2016

Member

@Egorand Thank you! 👍 Hence I'm closing this one.

Member

Godin commented Jul 26, 2016

@Egorand Thank you! 👍 Hence I'm closing this one.

@Godin Godin closed this Jul 26, 2016

@Godin Godin removed the feedback pending label Jul 26, 2016

@Egorand

This comment has been minimized.

Show comment
Hide comment
@Egorand

Egorand Jul 27, 2016

So it looks like the issue was fixed and will be included in the 3.0-rc-1 Gradle release.

Egorand commented Jul 27, 2016

So it looks like the issue was fixed and will be included in the 3.0-rc-1 Gradle release.

@Godin

This comment has been minimized.

Show comment
Hide comment
@Godin

Godin Jul 27, 2016

Member

@Egorand Cool! 😋 But I suppose that as usual they won't backport fix for older versions 😑

Member

Godin commented Jul 27, 2016

@Egorand Cool! 😋 But I suppose that as usual they won't backport fix for older versions 😑

@jacoco jacoco locked and limited conversation to collaborators Jan 11, 2017

Godin referenced this issue in vanniktech/gradle-android-junit-jacoco-plugin Feb 9, 2017

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.