bloop
bloop copied to clipboard
Favor NIO over IO to avoid FileSystemExceptions on Windows
On Windows, when Bloop compiled a project using a locally published JAR, it seems it still holds an exclusive access to the file. This is a problem when one wants to overwrite the locally published artifact from a build tool. One gets errors like
native.publishLocal java.nio.file.FileSystemException: C:\Users\Alex\.ivy2\local\io.github.alexarchambault.native-terminal\native-terminal\0.0.7-SNAPSHOT\jars\native-terminal.jar: The process cannot access the file because it is being used by another process
java.base/sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:92)
java.base/sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:103)
java.base/sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:108)
java.base/sun.nio.fs.WindowsFileSystemProvider.implDelete(WindowsFileSystemProvider.java:273)
java.base/sun.nio.fs.AbstractFileSystemProvider.delete(AbstractFileSystemProvider.java:104)
java.base/java.nio.file.Files.delete(Files.java:1152)
os.remove$all$.apply(FileOps.scala:341)
os.copy$over$.apply(FileOps.scala:300)
mill.scalalib.publish.LocalIvyPublisher.$anonfun$publishLocal$2(LocalIvyPublisher.scala:46)
scala.collection.immutable.List.map(List.scala:247)
scala.collection.immutable.List.map(List.scala:79)
mill.scalalib.publish.LocalIvyPublisher.publishLocal(LocalIvyPublisher.scala:44)
mill.scalalib.PublishModule.$anonfun$publishLocalTask$2(PublishModule.scala:231)
Restarting the Bloop server solves that problem, but isn't very handy.
Favoring Java NIO over Java IO seems to solve that problem, like done here or here.
This might help with semanticdb on Windows as well. Bloop clashing with Metals....
java.nio.file.FileSystemException: [XXX]\bloop-bsp-clients-classes\classes-Metals-GqF3NKlrSiGqKS_brmBrFg==\META-INF\semanticdb\src\main\scala\Foo.scala.semanticdb: The process cannot access the file because it is being used by another process
at sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:92)
at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:103)
at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:108)
at sun.nio.fs.WindowsFileSystemProvider.newByteChannel(WindowsFileSystemProvider.java:234)
at java.nio.file.Files.newByteChannel(Files.java:379)
at java.nio.file.Files.newByteChannel(Files.java:431)
at java.nio.file.spi.FileSystemProvider.newInputStream(FileSystemProvider.java:420)
at java.nio.file.Files.newInputStream(Files.java:159)
at scala.meta.internal.mtags.Semanticdbs$.loadTextDocuments(Semanticdbs.scala:24)
at scala.meta.internal.mtags.Semanticdbs$.loadResolvedTextDocument(Semanticdbs.scala:71)
at scala.meta.internal.mtags.Semanticdbs$.loadTextDocument(Semanticdbs.scala:55)
at scala.meta.internal.metals.FileSystemSemanticdbs.textDocument(FileSystemSemanticdbs.scala:67)
at scala.meta.internal.metals.AggregateSemanticdbs.loop$1(AggregateSemanticdbs.scala:30)
at scala.meta.internal.metals.AggregateSemanticdbs.textDocument(AggregateSemanticdbs.scala:36)
at scala.meta.internal.metals.CodeLensProvider.findLenses(CodeLensProvider.scala:25)
at scala.meta.internal.metals.MetalsLspService.$anonfun$codeLens$3(MetalsLspService.scala:1194)
at scala.meta.internal.metals.TimerProvider.timedThunk(TimerProvider.scala:25)
at scala.meta.internal.metals.MetalsLspService.$anonfun$codeLens$2(MetalsLspService.scala:1192)
at scala.concurrent.impl.Promise$Transformation.run(Promise.scala:470)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
at java.lang.Thread.run(Thread.java:1583)
Although the file might be unreadable anyway if it's only half written at this point
Hi! I’d like to pick up this issue.
From what I understand, the root cause is that Bloop is holding open file handles on Windows when reading JARs or semanticdb files via classic java.io APIs, preventing tools like Mill, Ivy, or Metals from overwriting or deleting those files.
Switching to NIO (Files.newInputStream, Files.newByteChannel, or using Path-based APIs with proper try-with-resources) should avoid those lingering handles.
My plan:
- Reproduce the lock behavior on Windows using a locally published JAR
- Identify where IO-based access is happening in Bloop’s classpath + jar handling
- Patch those locations to use NIO with explicit closing
- Verify that Mill/metals steps can overwrite/delete the JAR afterwards
If this sounds correct, could you please assign me @tgodzik ? I’m happy to work on a PR.