playframework/playframework — pull request #3591 by corruptmemory (2014-10-31 17:08:21+00:00)
Title: Initial implementation of a Forking-dev-mode runner

Uses sbt-remote-control to connect to a running sbt-server.

How it works:

If

`(fork in run) := true`

Then the run task will fork off the running play app executing the entry
point: `play.sbtclient.ForkRunner.main` passing it:

* base directory for the project
* build uri for the project
* target directory where output artifacts are generated
* project name
* http port
* https port
* poll delay milliseconds for the file watcher

The forked process will then connect back to the sbt-server via the
sbt-client interface. There is a custom task `playDefaultForkRunSupport`
that combines the execution of several tasks and emits them to a remote
client. This task generates sufficient information to create an
instance of Play's `BuildLink` interface and pass it to the Netty dev
main entry point. At this point things should more-or-less work the
same as in regular Play dev mode. Reloading works and errors and
compilation errors are correctly displayed in the web browser.

Known Limitations:

* If the project cannot be built the first time then the BuildLink
interface cannot be created and the forked process will exit
immediately. I think this can be addressed by having a different task
that feeds non-project classpath info to the forked child and sets the
reload status to true therefore capturing the error on first load.

* Java compilations failures are not handled. This is a known issue and
fixing this has been pushed upstream to the SBT team.

* Routes compilation failures are also not handled. Investigating
approaches for fixing this.

* Although much of what is needed is already in place in the
`ForkRunner` it is unclear how project reloading should be handled.
Not sure what sbt(-server)'s policy will be in this regard: kill
background tasks and restart or keep them running if forked. If the
policy will be to kill forked processes then nothing need be done.
Otherwise the ForkRunner can subscribe to build event changes and
"reboot" as necessary (which may not be needed as the `SbtClientProxy`
layer automatically resubscribes to watched tasks when a new client is
available)

Possible TO DOs:

* Since the forked process is "all Play" and not running within sbt it
may be possible to achieve some simplification in the code base. In
particular, the base application classpath: Netty, Play libs, external
dependencies can be made available on the boot classpath for the
forked process eliminating the need to do dynamic class loading.