From 22c9fd833a88e9ef3f5d65e78880395c3d04454c Mon Sep 17 00:00:00 2001 From: Edgar Espina Date: Sun, 3 Apr 2016 13:14:04 -0300 Subject: [PATCH] jooby:run with live compiler fix #338 --- .../src/main/java/org/jooby/JoobyMojo.java | 100 ++++++++++++++---- md/doc/maven-plugin/README.md | 21 +++- 2 files changed, 99 insertions(+), 22 deletions(-) diff --git a/jooby-maven-plugin/src/main/java/org/jooby/JoobyMojo.java b/jooby-maven-plugin/src/main/java/org/jooby/JoobyMojo.java index 36821fdffc..93c0aca9cf 100644 --- a/jooby-maven-plugin/src/main/java/org/jooby/JoobyMojo.java +++ b/jooby-maven-plugin/src/main/java/org/jooby/JoobyMojo.java @@ -25,14 +25,19 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; +import java.util.Arrays; import java.util.LinkedHashSet; import java.util.List; import java.util.Optional; import java.util.Properties; import java.util.Set; +import java.util.function.Consumer; import java.util.stream.Collectors; +import org.apache.maven.Maven; import org.apache.maven.artifact.Artifact; +import org.apache.maven.execution.DefaultMavenExecutionRequest; +import org.apache.maven.execution.MavenSession; import org.apache.maven.model.Resource; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; @@ -45,16 +50,48 @@ import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.plugins.annotations.ResolutionScope; import org.apache.maven.project.MavenProject; +import org.jooby.hotreload.Watcher; import com.google.common.io.Files; +import javaslang.control.Try; + @Mojo(name = "run", threadSafe = true, requiresDependencyResolution = ResolutionScope.TEST) @Execute(phase = LifecyclePhase.TEST_COMPILE) public class JoobyMojo extends AbstractMojo { + private static class ShutdownHook extends Thread { + private Log log; + + private List commands; + + private Watcher watcher; + + public ShutdownHook(final Log log, final List commands) { + this.log = log; + this.commands = commands; + setDaemon(true); + } + + @Override + public void run() { + if (watcher != null) { + log.info("stopping: watcher"); + Try.run(watcher::stop).onFailure(ex -> log.debug("Stop of watcher resulted in error", ex)); + } + commands.forEach(cmd -> { + log.info("stopping: " + cmd); + Try.run(cmd::stop).onFailure(ex -> log.error("Stop of " + cmd + " resulted in error", ex)); + }); + } + } + @Component private MavenProject mavenProject; + @Parameter(defaultValue = "${session}", required = true, readonly = true) + protected MavenSession session; + @Parameter(property = "main.class", defaultValue = "${application.class}") protected String mainClass; @@ -79,6 +116,12 @@ public class JoobyMojo extends AbstractMojo { @Parameter(defaultValue = "${plugin.artifacts}") private List pluginArtifacts; + @Parameter(property = "compiler", defaultValue = "on") + private String compiler; + + @Component + protected Maven maven; + @SuppressWarnings("unchecked") @Override public void execute() throws MojoExecutionException, MojoFailureException { @@ -141,10 +184,20 @@ public void execute() throws MojoExecutionException, MojoFailureException { cmd.setWorkdir(mavenProject.getBasedir()); getLog().debug("cmd: " + cmd.debug()); } + + Watcher watcher = setupCompiler(mavenProject, compiler, goal -> { + maven.execute(DefaultMavenExecutionRequest.copy(session.getRequest()) + .setGoals(Arrays.asList(goal))); + + }); + ShutdownHook shutdownHook = new ShutdownHook(getLog(), cmds); + shutdownHook.watcher = watcher; /** * Shutdown hook */ - Runtime.getRuntime().addShutdownHook(shutdownHook(cmds, getLog())); + Runtime.getRuntime().addShutdownHook(shutdownHook); + + watcher.start(); /** * Start process @@ -160,6 +213,33 @@ public void execute() throws MojoExecutionException, MojoFailureException { } + @SuppressWarnings("unchecked") + private static Watcher setupCompiler(final MavenProject project, final String compiler, + final Consumer task) throws MojoFailureException { + File eclipseClasspath = new File(project.getBasedir(), ".classpath"); + if ("off".equalsIgnoreCase(compiler) || eclipseClasspath.exists()) { + return null; + } + List resources = resources(project.getResources()); + resources.add(0, project.getBuild().getSourceDirectory()); + Path[] paths = new Path[resources.size()]; + for (int i = 0; i < paths.length; i++) { + paths[i] = Paths.get(resources.get(i)); + } + try { + return new Watcher((kind, path) -> { + if (path.toString().endsWith(".java")) { + task.accept("compile"); + } else if (path.toString().endsWith(".conf") + || path.toString().endsWith(".properties")) { + task.accept("compile"); + } + }, paths); + } catch (Exception ex) { + throw new MojoFailureException("Can't compile source code", ex); + } + } + private void dumpSysProps(final Path path) throws MojoFailureException { try { FileOutputStream output = new FileOutputStream(path.toFile()); @@ -334,7 +414,7 @@ private File localFile(final String... paths) { return result; } - private List resources(final Iterable resources) { + private static List resources(final Iterable resources) { List result = new ArrayList(); for (Resource resource : resources) { String dir = resource.getDirectory(); @@ -345,22 +425,6 @@ private List resources(final Iterable resources) { return result; } - private static Thread shutdownHook(final List cmds, final Log log) { - return new Thread() { - @Override - public void run() { - for (Command command : cmds) { - try { - log.info("stopping: " + command); - command.stop(); - } catch (Exception ex) { - log.error("Stopping process: " + command + " resulted in error", ex); - } - } - } - }; - } - private Optional extra(final List artifacts, final String name) { for (Artifact artifact : artifacts) { for (String tail : artifact.getDependencyTrail()) { diff --git a/md/doc/maven-plugin/README.md b/md/doc/maven-plugin/README.md index 08fb40ff9e..a9e836d484 100644 --- a/md/doc/maven-plugin/README.md +++ b/md/doc/maven-plugin/README.md @@ -1,6 +1,6 @@ # jooby:run -Increase development productivity: run, debug and auto-reload Jooby applications. +Increase development productivity: run, debug, compile and auto-reload Jooby applications. A {{maven}} plugin for running, debugging and reloading your application. @@ -34,9 +34,7 @@ The plugin bounces the application every time a change is detected on: Changes on templates and/or static files (*.html, *.js, *.css) wont restart the application, because they are not compiled/cached it while running on ```application.env = dev```. -**NOTE: For the time being, you need to use a tool that compiles your source code, usually an IDE. Otherwise, no changes will be found.** - -Is it worth to mention that dynamic reload of classes at runtime is done via {{jboss-modules}}. +Is it worth to mention that dynamic reload of classes is done via {{jboss-modules}}. ## options @@ -49,6 +47,7 @@ Is it worth to mention that dynamic reload of classes at runtime is done via {{j ${application.class} + on true @@ -66,6 +65,20 @@ Is it worth to mention that dynamic reload of classes at runtime is done via {{j A {{maven}} property that contains the fully qualified name of the ```main class```. **Required**. +### compiler + +The compiler is ```on``` by default, unless: + +* A ```.classpath``` file is present in the project directory. If present, means you're a Eclipse user and we turn off the compiler and let Eclipse recompiles the code on save. + +* The compiler is set to ```off```. + +On compilation success, the application is effectively reloaded. + +On compilation error, the application won't reload. + +Compilation success or error messages are displayed in the console (not at the browser). + ### debug The JVM is started in **debug mode by default**. You can attach a remote debugger at the ```8000``` port.