jaspervdj/hakyll — pull request #155 by blaenk (2013-05-22 11:06:30+00:00)
Title: fix preview functionality on windows

As #153 states, preview functionality is currently broken in master due to the merging of @simukis' code in 5f6035b . The changes he suggested are overall better, in my opinion, as they utilize operating systems' specific file event notifications APIs. The problem is that on Windows, the API often used for this reason -- and the API consequently exposed by [fs-notify](http://hackage.haskell.org/package/fsnotify) (by way of [win32-notify](http://hackage.haskell.org/package/Win32-notify)) -- has a flaw/difference in the way it handles file modification events.

In essence, the problem that is experienced on Windows is that the file modification event is sent/received before the program doing the modification is even done doing the modification (i.e. before it is finished writing to the file). As the code currently stands, Hakyll immediately upon receipt of the event attempts to read the file (in order to generate the changes) and the operation fails with a 'permission denied' error because the program (e.g. editor) still hasn't relinquished writing control of the file.

For more information, please refer to [this post](https://github.com/mdittmer/win32-notify/issues/3#issuecomment-18260415) in the issue I created for win32-notify, which summarizes my findings.

As is mentioned there, I don't think this is a flaw in win32-notify, as it's simply exposing the API more or less verbatim in its bindings. As the post shows, this is simply a recurring problem encountered by people using the [`ReadDirectoryChangesW`](http://msdn.microsoft.com/en-us/library/windows/desktop/aa365465.aspx) API. I don't think it's something that can be (or maybe even, shouldn't be) implemented in win32-notify because that would embed the assumption that all users of the library want/need to open/read the file for which the event occurred. It could be they're simply logging events to some other place.

What I found was that the common workaround for this is to simply keep trying to open the file until it is possible to, then continue with the operation dependent on being able to open/read the file. This is what I have done.

This inevitably introduces CPP conditionals which I've tried to keep to a minimum, and as neat/clean as possible. The way the workaround works is by attempting to open the file, and if a permission denied exception is raised, sleep for 100 milliseconds before attempting once again. I've been using it on my end and now preview functionality works perfectly, and is quite fast.

The only other alternative I can imagine is to force the usage of the polling interface that fs-notify exposes, though I haven't tested this myself. This would revert preview behavior to pre-fs-notify state. The disadvantage is that all files in the provider directory would be constantly polled, instead of a more 'push' notification-like behavior when using the actual operating system's file event notifications API. It's true that this workaround is a bit similar to polling, but it would only be occurring for the file for which the event occurred, instead of for every single file.

Let me know what you think.