scoverage / scalac-scoverage-plugin

Scoverage Scala Code Coverage Core Libs
https://github.com/scoverage
Apache License 2.0
426 stars 126 forks source link

Scoverage does not close source files after reading #371

Closed lefou closed 3 years ago

lefou commented 3 years ago

I have the issue that our mill test suite fails in subsequent scoverage plugin tests on Windows. Between each run we clean the complete work directory, but we don't drop the JVM which runs the scalac-scoverage-plugin. As a result we can't clean our workdir because the source files, which were processed are still locked. Windows locks files as long as one process keeps it open. So my suspicion is, that somewhere in scoverage, the Scala source files were opened but not properly closed. We get this message:

java.nio.file.FileSystemException: D:\a\mill\mill\target\worksources\mill\contrib\scoverage\HelloWorldTests#HelloWorld\core\src\Greet.scala: The process cannot access the file because it is being used by another process.

    sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:86)
    sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:97)
    sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:102)
    sun.nio.fs.WindowsFileSystemProvider.implDelete(WindowsFileSystemProvider.java:269)
    sun.nio.fs.AbstractFileSystemProvider.delete(AbstractFileSystemProvider.java:103)
    java.nio.file.Files.delete(Files.java:1126)
    os.remove$.apply(FileOps.scala:285)
    os.remove$.apply(FileOps.scala:284)
    geny.Generator.$anonfun$foreach$1(Generator.scala:50)
    geny.Generator$Mapped.$anonfun$generate$4(Generator.scala:283)
    os.walk$stream$$anon$2$$anon$3.visitFile(ListOps.scala:249)
    os.walk$stream$$anon$2$$anon$3.visitFile(ListOps.scala:230)
    java.nio.file.Files.walkFileTree(Files.java:2670)
    os.walk$stream$$anon$2.generate(ListOps.scala:230)
    geny.Generator$Mapped.generate(Generator.scala:283)
    geny.Generator.foreach(Generator.scala:49)
    geny.Generator.foreach$(Generator.scala:49)
    geny.Generator$Mapped.foreach(Generator.scala:281)
    os.remove$all$.apply(FileOps.scala:294)
    mill.contrib.scoverage.HelloWorldTests.workspaceTest(HelloWorldTests.scala:67)
    mill.contrib.scoverage.HelloWorldTests.workspaceTest$(HelloWorldTests.scala:62)
    mill.contrib.scoverage.HelloWorldTests_2_12$.workspaceTest(HelloWorldTests.scala:191)
    mill.contrib.scoverage.HelloWorldTests.$anonfun$tests$30(HelloWorldTests.scala:74)

Of course the stack trace belongs to the point, where we try to delete the file. But as it seems to be already opened (and locked) it fails.

This can't be reproduced on non-Windows machines

After a chat on Gitter @ckipp01 probably located the suspected issue at: https://github.com/scoverage/scalac-scoverage-plugin/blob/8528c10fe3712e729f4a20bfda461e30abe36f59/scalac-scoverage-plugin/src/main/scala/scoverage/report/CodeGrid.scala#L77-L83

A naive fix could look like this:

@@ -79,7 +78,8 @@ class CodeGrid(mFile: MeasuredFile, sourceEncoding: Option[String]) {
       case Some(enc) => Source.fromFile(mfile.source, enc)
       case None      => Source.fromFile(mfile.source)
     }
-    src.mkString
+    try src.mkString
+    finally src.close()
   }

   private def spanStart(status: StatementStatus): String =