Bloop: Emacs interlock files break Bloop compile

Created on 11 Nov 2019  路  14Comments  路  Source: scalacenter/bloop

When a buffer is modified, Emacs creates an interlock file in order to detect and prevent another user (or another Emacs instance) from editing the same file and possibly overwriting changes. These interlock files have the form .#filename and (at least on Linux) are symlinks to a non-existent file whose names encodes the user and process that has unsaved modifications to the file.

ls -al .#*
lrwxrwxrwx 1 marc marc 33 Nov 11 09:11 .#Day10.scala -> [email protected]:1573423575

The existence of one of these interlock files breaks Bloop compiles:

[E] Failed to compile 'advent2016'
Watching 1 directories... (press Ctrl-C to interrupt)
[E] File watching threw an exception:
/home/marc/work/AdventOfCode2016/src/main/scala/.#Day10.scala

The interlock files are deleted when a file is saved so there may be timing issues as well depending on when Bloop sees the modified files and when Emacs deletes the interlock file. SBT is not affected at all by the existence of these interlock files.

I encountered this issue via Metals and it is being discussed as issue 956 there. Within Emacs/Metals, this error manifests as compile errors not being updated as code changes. New errors do not get highlighted and fixed errors don't get removed. Forcing a Bloop compile when there are no interlock files appears to clear the problem until another interlock is created.

The only work-around is to disable the creation of interlock files by setting the Emacs variable create-lockfiles to nil.

bug task / watch

Most helpful comment

Hi Marc, this project is a safe place for people learn, teach and contribute. Your snarky and negative tone is not welcome here, I encourage you to improve your attitude.

Feel free to send a PR blacklisting interlock files from the file watcher. We don't need to fix this in the file watching library we use, this is a problem niche enough that I'm okay with merging a brute-force solution.

All 14 comments

Hi @marcsaegesser, thanks for reporting! It looks this could be fixed in SourceWatcher.scala by intentionally skipping these interlock files. I would also re-run the command with --verbose to have more information about the type of exception thrown by the file watcher, that should tell us what's at fault here.

Is this issue something you'd be interested in working on?

Running with --verbose I get the following (with the very annoying ANSI escape codes removed):

Loading workspace settings from bloop.settings.json

Computing sources and classpath hashes for advent2016
Failed to compile 'advent2016'
Watching 1 directories... (press Ctrl-C to interrupt)
/home/marc/work/AdventOfCode2016/src/main/scala
Assuming ExtendedWatchEventModifier.FILE_TREE is not supported
/home/marc/work/AdventOfCode2016/src/main/scala
ENTRY_CREATE
/home/marc/work/AdventOfCode2016/src/main/scala/.#Day11.scala
/home/marc/work/AdventOfCode2016/src/main/scala/.#Day11.scala
ENTRY_MODIFY
/home/marc/work/AdventOfCode2016/src/main/scala/Day11.scala
Received List(DirectoryChangeEvent{eventType=MODIFY, path=/home/marc/work/AdventOfCode2016/src/main/scala/Day11.scala, count=1}) in file watcher consumer

A MODIFY in /home/marc/work/AdventOfCode2016/src/main/scala/Day11.scala has triggered an event
Computing sources and classpath hashes for advent2016
Failed to compile 'advent2016'
Watching 1 directories... (press Ctrl-C to interrupt)
ENTRY_DELETE
/home/marc/work/AdventOfCode2016/src/main/scala/.#Day11.scala
DirectoryWatcher got an exception while watching!
File watching threw an exception: /home/marc/work/AdventOfCode2016/src/main/scala/.#Day11.scala

Unfortunately, Bloop doesn't show the actual exception, just the exception's message, so I can't tell what actually went wrong or where. Given that this gets reported in the onException() callback the exception obviously comes from within io.methvin.watcher.DirectoryWatcher. After a quick look through that project I don't see any place where it throws an exception whose message is just the path name. That means it's probably coming from java.nio.file.WatchService. If I had to guess I'd say that WatchService is throwing something like a NoSuchFileException that should really be ignored but is being treated as fatal and preventing the onEvent() callback from being called and thus Bloop doesn't do any compilation on the modified files. Again, all guesswork.

I followed the instructions in "Contributing to Bloop" but SBT fails to find a dependency:

[error] sbt.librarymanagement.ResolveException: Error downloading com.dwijnand:sbt-compat;sbtVersion=1.0;scalaVersion=2.12:1.0.0

So I can't build Bloop myself to try to get the details on the exception to see how close my guesswork is. If someone can clue me in to how to get Bloop to build I can experiment a little more but I don't have a lot of extra cycles to debug the Internet.

That's quite a weird error. My guess is that you're using an sbt launcher that is old. I recommend running brew upgrade sbt and trying to get bloop set up again.

It's Linux, not Mac, and I'd triple checked it was the most recent version. I blew away some stuff under ~/.sbt/1.0 and that fixed that problem. There was probably an old plugin in there with some outdated dependencies. Why it only failed for Bloop is a mystery I just don't care to solve.

The build then failed because there's a dependency on clang that's not listed in the installation notes. It would be nice to include a list of the platform packages that are required in order to build Bloop. After installing clang I was able to finally get to an sbt prompt.

I'm now at a point where I might be able to get some actual data. Which will probably show a problem in a library Bloop depends on and my journey to once again having a functional Scala/Emacs environment will continue further down a well of sorrow and grief.

Luckily, I enjoy being grumpy.

Hi Marc, this project is a safe place for people learn, teach and contribute. Your snarky and negative tone is not welcome here, I encourage you to improve your attitude.

Feel free to send a PR blacklisting interlock files from the file watcher. We don't need to fix this in the file watching library we use, this is a problem niche enough that I'm okay with merging a brute-force solution.

OK, no more snark.

It's a timing problem that happens when the compilation gets started before the file deletion actually happens. The exception from the directory watcher was a complete red herring.

The code below is from CompileTask.scala at line 295. I commented out the original wildcard match that quietly ate supposed non-errors and replaced it with a log statement. Below is the output from a verbose watch. You can see the extra logging prefixed by "Not an actual error". Note the "Unexpected exception when computing compile inputs" near the end. That breaks the compile so whatever should have resulted from the MODIFY event is lost. If you do it enough times it will sometimes happen that the delete completes before the compile begins and then everything works OK.

This can't be solved by simply filtering the out the .#* files in SourceWatcher because it isn't actually those files causing the problem, it's that some files got deleted during compilation. I'm not sure how to solve this. Maybe adding a delay after MODIFY events before actually doing compilation or detecting this type of error and re-running the compilation?

            results.foreach {
              case FinalNormalCompileResult.HasException(project, t) =>
                rawLogger
                  .error(s"Unexpected error when compiling ${project.name}: '${t.getMessage}'")
                rawLogger.trace(t)
              // case _ => () // Do nothing when the final compilation result is not an actual error
              case x => rawLogger.error(s"Not an actual error:  $x") // Do nothing when the final compilation result is not an actual error
            }

[D] A MODIFY in /home/marc/work/AdventOfCode2016/src/main/scala/Day11.scala has triggered an event
[D] Computing sources and classpath hashes for advent2016
[D] ENTRY_DELETE
[D] /home/marc/work/AdventOfCode2016/src/main/scala/.#Day11.scala
[D] DirectoryWatcher got an exception while watching!
[D] File watching threw an exception: /home/marc/work/AdventOfCode2016/src/main/scala/.#Day11.scala - java.nio.file.NoSuchFileException: /home/marc/work/AdventOfCode2016/src/main/scala/.#Day11.scala
[D] File watching threw an exception: /home/marc/work/AdventOfCode2016/src/main/scala/.#Day11.scala - ()
[E] Not an actual error: FinalEmptyResult
[E] Not an actual error: FinalNormalCompileResult(advent2016,ResultBundle(GlobalError(Unexpected exception when computing compile inputs /home/marc/work/AdventOfCode2016/src/main/scala/.#Day11.scala (No such file or directory)),None,None,monix.execution.CancelableFuture$Now@6d80b1af))
[E] Failed to compileX 'advent2016'

I'm going to have a closer look at this and will try to fix it and release it after Christmas @marcsaegesser

@jvican I believe I am experiencing this as well in Spacemacs on Mac. Anything I can do to help, or any information I can provide you with? My Spacemacs is set up to use Metals, which I understand uses Bloop. But I'm new to Scala and it's ecosystem.

Thanks for confirming that, I should have a look at this shortly :+1: Will keep you in the loop and let you know if there's anything you can do

I appreciate it, Jorge!

I'm also encountering this issue on Doom Emacs, using latest Metals version and Bloop 1.4.0-RC1.

I've had another look at this problem. I believe the solution to this problem is not a delay, but instead filtering out the interlock files from SourceWatcher as well as filtering them out from the source hashing that occurs in CompileInputs.

@marcsaegesser @Kazark @ashkan-leo I've created a PR with this change, I'll merge it as soon as CI is passing so that you can confirm if this issue is finally fixed or not. Let me know your thoughts if you have any

Thanks a lot @jvican!

PR is merged. As soon as the CI runs there will be a version published and referenced in the website here https://scalacenter.github.io/bloop/setup

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jvican picture jvican  路  4Comments

aishfenton picture aishfenton  路  3Comments

dsilvasc picture dsilvasc  路  8Comments

kai-ming-91 picture kai-ming-91  路  5Comments

ayoub-benali picture ayoub-benali  路  4Comments