diff --git a/pom.xml b/pom.xml index 68e4ce35..29078585 100644 --- a/pom.xml +++ b/pom.xml @@ -1,18 +1,20 @@ - + 4.0.0 org.sonatype.oss oss-parent - 7 + 9 br.com.ingenieux jbake-maven-plugin maven-plugin - 0.0.7-SNAPSHOT + 0.3.0-SNAPSHOT - 3.1.1 + 3.1.1 jbake-maven-plugin is a plugin to integrate JBake into your projects @@ -49,7 +51,7 @@ github - https://bitbucket.org/ingenieux/jbake-maven-plugin/ + https://github.com/ingenieux/jbake-maven-plugin/ @@ -59,9 +61,10 @@ - scm:hg:http://bitbucket.org/ingenieux/jbake-maven-plugin - scm:hg:ssh://hg@bitbucket.org/ingenieux/jbake-maven-plugin - http://bitbucket.org/ingenieux/jbake-maven-plugin + scm:git:http://github.com/ingenieux/jbake-maven-plugin + scm:git:ssh://git@github.com/ingenieux/jbake-maven-plugin.git + + http://github.com/ingenieux/jbake-maven-plugin @@ -75,6 +78,18 @@ + + com.sparkjava + spark-core + + + org.eclipse.jetty + jetty-util + + + org.eclipse.jetty + jetty-server + org.apache.maven maven-plugin-api @@ -105,17 +120,18 @@ plexus-utils - io.vertx - vertx-core + commons-io + commons-io - io.vertx - vertx-platform + org.freemarker + freemarker + 2.3.22 - commons-io - commons-io - 2.4 + org.asciidoctor + asciidoctorj + 1.5.2 @@ -124,43 +140,48 @@ org.jbake jbake-core - 2.2.1 + 2.4.0 org.apache.maven maven-plugin-api - 3.0.4 + 3.3.9 commons-lang commons-lang 2.6 + + commons-io + commons-io + 2.4 + org.apache.maven.plugin-testing maven-plugin-testing-harness - 2.0-alpha-1 + 3.3.0 test log4j log4j - 1.2.12 + 1.2.17 org.apache.maven maven-settings - 3.0.4 + 3.3.9 org.apache.maven maven-core - 3.0.4 + 3.3.9 org.apache.maven.plugin-tools maven-plugin-annotations - 3.2 + 3.4 provided @@ -171,17 +192,22 @@ org.codehaus.plexus plexus-utils - 3.0.1 + 3.0.22 + + + com.sparkjava + spark-core + 2.3 - io.vertx - vertx-core - 2.0.2-final + org.eclipse.jetty + jetty-util + 9.3.2.v20150730 - io.vertx - vertx-platform - 2.0.2-final + org.eclipse.jetty + jetty-server + 9.3.2.v20150730 @@ -195,52 +221,58 @@ - - - - org.apache.maven.plugins - maven-plugin-plugin - 3.2 - true - - - 1.7 - - true - - - - mojo-descriptor - - descriptor - - - - - help-goal - - helpmojo - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.1 - - - 1.7 - 1.7 - - - - org.apache.maven.plugins - maven-site-plugin - 3.3 - - - + + + org.apache.maven.plugins + maven-plugin-plugin + 3.4 + + jbake + + 1.8 + + true + + + + default-descriptor + process-classes + + + help-goal + + helpmojo + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.3 + + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.10.3 + + + attach-javadocs + + jar + + + -Xdoclint:none + + + + + @@ -248,23 +280,23 @@ org.apache.maven.plugins maven-project-info-reports-plugin - 2.6 + 2.8.1 org.apache.maven.plugins maven-plugin-plugin - 3.2 + 3.4 org.apache.maven.plugins maven-javadoc-plugin - 2.9 + 2.10.3 org.apache.maven.plugins maven-jxr-plugin - 2.3 + 2.5 - + \ No newline at end of file diff --git a/src/main/java/br/com/ingenieux/mojo/jbake/GenerateMojo.java b/src/main/java/br/com/ingenieux/mojo/jbake/GenerateMojo.java index 2f1e55ce..4f41b6ff 100644 --- a/src/main/java/br/com/ingenieux/mojo/jbake/GenerateMojo.java +++ b/src/main/java/br/com/ingenieux/mojo/jbake/GenerateMojo.java @@ -16,10 +16,19 @@ * limitations under the License. */ +import com.orientechnologies.orient.core.Orient; + +import org.apache.commons.configuration.CompositeConfiguration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.commons.configuration.MapConfiguration; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.plugins.annotations.ResolutionScope; +import org.apache.maven.project.MavenProject; +import org.jbake.app.ConfigUtil; +import org.jbake.app.JBakeException; import org.jbake.app.Oven; import java.io.File; @@ -27,30 +36,78 @@ /** * Runs jbake on a folder */ -@Mojo(name = "generate", requiresProject = false) +@Mojo(name = "generate", requiresProject = true, requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME) public class GenerateMojo extends AbstractMojo { - /** - * Location of the Output Directory. - */ - @Parameter(property = "jbake.outputDirectory", defaultValue = "${project.build.directory}/${project.build.finalName}", required = true) - protected File outputDirectory; - - /** - * Location of the Output Directory. - */ - @Parameter(property = "jbake.inputDirectory", defaultValue = "${project.basedir}/src/main/jbake", required = true) - protected File inputDirectory; - - public void execute() throws MojoExecutionException { - try { - Oven oven = new Oven(inputDirectory, outputDirectory); - - oven.setupPaths(); - oven.bake(); - } catch (Exception e) { - getLog().info("Oops", e); - - throw new MojoExecutionException("Failure when running: ", e); - } - } + @Parameter(defaultValue="${project}") + protected MavenProject project; + + /** + * Location of the Output Directory. + */ + @Parameter(property = "jbake.outputDirectory", + defaultValue = "${project.build.directory}/${project.build.finalName}", + required = true) + protected File outputDirectory; + + /** + * Location of the Output Directory. + */ + @Parameter(property = "jbake.inputDirectory", defaultValue = "${project.basedir}/src/main/jbake", + required = true) + protected File inputDirectory; + + /** + * Set if cache is present or clear + */ + @Parameter(property = "jbake.isClearCache", defaultValue = "false", required = true) + protected boolean isClearCache; + + public final void execute() throws MojoExecutionException { + try { + executeInternal(); + } finally { + closeQuietly(); + } + } + + protected final void closeQuietly() { + try { + Orient.instance().shutdown(); + } catch (Exception e) { + getLog().warn("Oops", e); + } + } + + protected void executeInternal() throws MojoExecutionException { + reRender(); + } + + protected void reRender() throws MojoExecutionException { + try { + // TODO: Smells bad. A lot + Orient.instance().startup(); + + // TODO: At some point, reuse Oven + Oven oven = new Oven(inputDirectory, outputDirectory, createConfiguration(), isClearCache); + + oven.setupPaths(); + + oven.bake(); + } catch (Exception e) { + getLog().info("Oops", e); + + throw new MojoExecutionException("Failure when running: ", e); + } + } + + protected CompositeConfiguration createConfiguration() throws ConfigurationException { + final CompositeConfiguration config = new CompositeConfiguration(); + + config.addConfiguration(ConfigUtil.load(inputDirectory)); + + config.addConfiguration(new MapConfiguration(this.project.getProperties())); + + return config; + } + } diff --git a/src/main/java/br/com/ingenieux/mojo/jbake/InlineMojo.java b/src/main/java/br/com/ingenieux/mojo/jbake/InlineMojo.java index df2d6435..e11d85c7 100644 --- a/src/main/java/br/com/ingenieux/mojo/jbake/InlineMojo.java +++ b/src/main/java/br/com/ingenieux/mojo/jbake/InlineMojo.java @@ -19,65 +19,50 @@ import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; -import org.vertx.java.core.Handler; -import org.vertx.java.core.VertxFactory; -import org.vertx.java.core.http.HttpServerRequest; -import org.vertx.java.platform.Verticle; -import java.io.File; +import static spark.Spark.awaitInitialization; +import static spark.Spark.externalStaticFileLocation; +import static spark.Spark.init; +import static spark.Spark.ipAddress; +import static spark.Spark.port; +import static spark.Spark.stop; /** * Runs jbake on a folder while watching and serving a folder with it */ @Mojo(name = "inline", requiresDirectInvocation = true, requiresProject = false) public class InlineMojo extends WatchMojo { - /** - * Listen Port - */ - @Parameter(property = "jbake.listenAddress", defaultValue = "127.0.0.1") - private String listenAddress; - /** - * Index File - */ - @Parameter(property = "jbake.indexFile", defaultValue = "index.html") - private String indexFile; + /** + * Listen Port + */ + @Parameter(property = "jbake.listenAddress", defaultValue = "127.0.0.1") + private String listenAddress; - /** - * Listen Port - */ - @Parameter(property = "jbake.port", defaultValue = "8080") - private Integer port; + /** + * Index File + */ + @Parameter(property = "jbake.indexFile", defaultValue = "index.html") + private String indexFile; - Server server = new Server(); + /** + * Listen Port + */ + @Parameter(property = "jbake.port", defaultValue = "8080") + private Integer port; - class Server extends Verticle { - { - vertx = VertxFactory.newVertx(); - } + protected void stopServer() throws MojoExecutionException { + stop(); + } - @Override - public void start() { - vertx.createHttpServer().requestHandler(new Handler() { - @Override - public void handle(HttpServerRequest req) { - String file = req.path().endsWith("/") ? req.path() + indexFile : req.path(); + protected void initServer() throws MojoExecutionException { + externalStaticFileLocation(outputDirectory.getPath()); - if (new File(outputDirectory + file).isDirectory()) { - req.response().setStatusCode(301).putHeader("Location", file + "/").close(); - } else { - req.response().sendFile(outputDirectory.getAbsolutePath() + file); - } - } - }).listen(port, listenAddress); - } - } + ipAddress(listenAddress); + port(this.port); - protected void stopServer() { - server.stop(); - } + init(); - protected void initServer() throws MojoExecutionException { - server.start(); - } + awaitInitialization(); + } } diff --git a/src/main/java/br/com/ingenieux/mojo/jbake/WatchMojo.java b/src/main/java/br/com/ingenieux/mojo/jbake/WatchMojo.java index 38d67212..2ad69f5e 100644 --- a/src/main/java/br/com/ingenieux/mojo/jbake/WatchMojo.java +++ b/src/main/java/br/com/ingenieux/mojo/jbake/WatchMojo.java @@ -16,76 +16,97 @@ * limitations under the License. */ -import br.com.ingenieux.mojo.jbake.util.DirWatcher; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugins.annotations.Mojo; import java.io.BufferedReader; import java.io.InputStreamReader; -import java.nio.file.Paths; import java.util.concurrent.atomic.AtomicBoolean; +import br.com.ingenieux.mojo.jbake.util.DirWatcher; + +import static org.apache.commons.lang.StringUtils.isBlank; + /** * Runs jbake on a folder while watching for changes */ @Mojo(name = "watch", requiresDirectInvocation = true, requiresProject = false) public class WatchMojo extends GenerateMojo { - public void execute() throws MojoExecutionException { - super.execute(); - - getLog().info( - "Now listening for changes on path " + inputDirectory.getPath()); - - initServer(); - - try { - final AtomicBoolean done = new AtomicBoolean(false); - final BufferedReader reader = new BufferedReader( - new InputStreamReader(System.in)); - - (new Thread() { - @Override - public void run() { - try { - getLog().info("Running. Hit to finish"); - reader.readLine(); - } catch (Exception exc) { - } finally { - done.set(true); - } - } - }).start(); - - DirWatcher dirWatcher = new DirWatcher(Paths.get(inputDirectory - .getPath())); - - do { - Boolean result = dirWatcher.processEvents(); - - if (Boolean.FALSE.equals(result)) { - Thread.sleep(1000); - } else if (Boolean.TRUE.equals(result)) { - getLog().info("Refreshing"); - - super.execute(); - } else if (null == result) { - break; - } - } while (!done.get()); - } catch (Exception exc) { - getLog().info("Oops", exc); - - throw new MojoExecutionException("Oops", exc); - } finally { - getLog().info("Finishing"); - - stopServer(); - } - } - - protected void stopServer() { - } - - protected void initServer() throws MojoExecutionException { - } + + public void executeInternal() throws MojoExecutionException { + reRender(); + + Long lastProcessed = Long.valueOf(System.currentTimeMillis()); + + getLog().info( + "Now listening for changes on path " + inputDirectory.getPath()); + + initServer(); + + DirWatcher dirWatcher = null; + + try { + dirWatcher = new DirWatcher(inputDirectory); + final AtomicBoolean done = new AtomicBoolean(false); + final BufferedReader reader = new BufferedReader( + new InputStreamReader(System.in)); + + (new Thread() { + @Override + public void run() { + try { + getLog() + .info("Running. Enter a blank line to finish. Anything else forces re-rendering."); + + while (true) { + String line = reader.readLine(); + + if (isBlank(line)) { + break; + } + + reRender(); + } + } catch (Exception exc) { + getLog().info("Ooops", exc); + } finally { + done.set(true); + } + } + }).start(); + + dirWatcher.start(); + + do { + Long result = dirWatcher.processEvents(); + + if (null == result) { + // do nothing on purpose + } else if (result >= lastProcessed) { + getLog().info("Refreshing"); + + super.reRender(); + + lastProcessed = Long.valueOf(System.currentTimeMillis()); + } + } while (!done.get()); + } catch (Exception exc) { + getLog().info("Oops", exc); + + throw new MojoExecutionException("Oops", exc); + } finally { + getLog().info("Finishing"); + + if (null != dirWatcher) + dirWatcher.stop(); + + stopServer(); + } + } + + protected void stopServer() throws MojoExecutionException { + } + + protected void initServer() throws MojoExecutionException { + } } diff --git a/src/main/java/br/com/ingenieux/mojo/jbake/util/DirWatcher.java b/src/main/java/br/com/ingenieux/mojo/jbake/util/DirWatcher.java index 42f839cd..d46f4934 100644 --- a/src/main/java/br/com/ingenieux/mojo/jbake/util/DirWatcher.java +++ b/src/main/java/br/com/ingenieux/mojo/jbake/util/DirWatcher.java @@ -1,24 +1,13 @@ package br.com.ingenieux.mojo.jbake.util; -import static java.nio.file.LinkOption.NOFOLLOW_LINKS; -import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE; -import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE; -import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY; -import static java.nio.file.StandardWatchEventKinds.OVERFLOW; +import org.apache.commons.io.monitor.FileAlterationListenerAdaptor; +import org.apache.commons.io.monitor.FileAlterationMonitor; +import org.apache.commons.io.monitor.FileAlterationObserver; +import java.io.File; import java.io.IOException; -import java.nio.file.FileSystems; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.SimpleFileVisitor; -import java.nio.file.WatchEvent; -import java.nio.file.WatchEvent.Kind; -import java.nio.file.WatchKey; -import java.nio.file.WatchService; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.HashMap; -import java.util.Map; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; import java.util.concurrent.TimeUnit; /** @@ -26,121 +15,52 @@ */ public class DirWatcher { - private final WatchService watcher; - private final Map keys; - - @SuppressWarnings("unchecked") - static WatchEvent cast(WatchEvent event) { - return (WatchEvent) event; - } - - /** - * Register the given directory with the WatchService - */ - private void register(Path dir) throws IOException { - WatchKey key = dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE, - ENTRY_MODIFY); - // if (trace) { - // Path prev = keys.get(key); - // if (prev == null) { - // System.out.format("register: %s\n", dir); - // } else { - // if (!dir.equals(prev)) { - // System.out.format("update: %s -> %s\n", prev, dir); - // } - // } - // } - keys.put(key, dir); - } - - /** - * Register the given directory, and all its sub-directories, with the - * WatchService. - */ - private void registerAll(final Path start) throws IOException { - // register directory and sub-directories - Files.walkFileTree(start, new SimpleFileVisitor() { - @Override - public FileVisitResult preVisitDirectory(Path dir, - BasicFileAttributes attrs) throws IOException { - register(dir); - return FileVisitResult.CONTINUE; - } - }); - } - - /** - * Creates a WatchService and registers the given directory - */ - public DirWatcher(Path dir) throws IOException { - this.watcher = FileSystems.getDefault().newWatchService(); - this.keys = new HashMap(); - - registerAll(dir); - } - - /** - * Process all events for keys queued to the watcher - */ - public Boolean processEvents() { - // wait for key to be signalled - WatchKey key; - try { - key = watcher.poll(1L, TimeUnit.SECONDS); - } catch (InterruptedException x) { - return Boolean.FALSE; - } - - if (null == key) - return Boolean.FALSE; - - Path dir = keys.get(key); - if (dir == null) - throw new IllegalStateException("WatchKey not recognized!!"); - - for (WatchEvent event : key.pollEvents()) { - Kind kind = event.kind(); - - // TBD - provide example of how OVERFLOW event is handled - if (kind == OVERFLOW) { - continue; - } - - // Context for directory entry event is the file name of entry - WatchEvent ev = cast(event); - Path name = ev.context(); - Path child = dir.resolve(name); - - // if directory is created, and watching recursively, then - // register it and its sub-directories - if (kind == ENTRY_CREATE) { - try { - if (Files.isDirectory(child, NOFOLLOW_LINKS)) { - registerAll(child); - } - } catch (IOException x) { - // ignore to keep sample readbale - } - } - } - - // reset key and remove from set if directory no longer accessible - boolean valid = key.reset(); - if (!valid) { - keys.remove(key); - - // all directories are inaccessible - if (keys.isEmpty()) { - return null; - } - } - - return Boolean.TRUE; - } - - static void usage() { - System.err.println("usage: java WatchDir [-r] dir"); - System.exit(-1); - } + private final FileAlterationObserver observer; + + private final FileAlterationMonitor monitor; + + private final BlockingQueue changeQueue = new ArrayBlockingQueue(1); + + /** + * Creates a WatchService and registers the given directory + */ + public DirWatcher(File dir) throws IOException { + this.observer = new FileAlterationObserver(dir); + this.monitor = new FileAlterationMonitor(1000, observer); + + observer.addListener(new FileAlterationListenerAdaptor() { + @Override + public void onFileCreate(File file) { + onUpdated(); + } + + @Override + public void onFileChange(File file) { + onUpdated(); + } + }); + } + + public void start() throws Exception { + monitor.start(); + } + + public void stop() { + try { + monitor.stop(); + } catch (Exception exc) { + } + } + + private void onUpdated() { + changeQueue.add(Long.valueOf(System.currentTimeMillis())); + } + + /** + * Process all events for keys queued to the watcher + */ + public Long processEvents() throws InterruptedException { + return changeQueue.poll(1, TimeUnit.SECONDS); + } } \ No newline at end of file diff --git a/src/main/resources/META-INF/plexus/components.xml b/src/main/resources/META-INF/plexus/components.xml new file mode 100644 index 00000000..50b1ab4c --- /dev/null +++ b/src/main/resources/META-INF/plexus/components.xml @@ -0,0 +1,28 @@ + + + + org.apache.maven.lifecycle.mapping.LifecycleMapping + jbake + org.apache.maven.lifecycle.mapping.DefaultLifecycleMapping + + + + default + + ${project.groupId}:${project.artifactId}:${project.version}:generate + + + + site + + + ${project.groupId}:${project.artifactId}:${project.version}:generate + + + + + + + + + \ No newline at end of file