blob: 75801f99d3aa80e5bb88781db0852e27e9807ac2 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.meecrowave.doc;
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 java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintStream;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.nio.file.ClosedWatchServiceException;
import java.nio.file.Path;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Scanner;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Stream;
import org.apache.commons.configuration.CompositeConfiguration;
import org.apache.commons.configuration.MapConfiguration;
import org.apache.meecrowave.Meecrowave;
import org.apache.meecrowave.doc.generator.ArquillianConfiguration;
import org.apache.meecrowave.doc.generator.CliConfiguration;
import org.apache.meecrowave.doc.generator.Configuration;
import org.apache.meecrowave.doc.generator.Downloads;
import org.apache.meecrowave.doc.generator.GradleConfiguration;
import org.apache.meecrowave.doc.generator.LetsEncryptConfiguration;
import org.apache.meecrowave.doc.generator.MavenConfiguration;
import org.apache.meecrowave.doc.generator.OAuth2Configuration;
import org.apache.meecrowave.doc.generator.ProxyConfiguration;
import org.jbake.app.Oven;
import org.jbake.app.configuration.ConfigUtil;
import org.jbake.app.configuration.DefaultJBakeConfiguration;
import com.orientechnologies.orient.core.Orient;
public class JBake {
private JBake() {
// no-op
}
// if you want to switch off PDF generation use as arguments: src/main/jbake target/site-tmp true false
public static void main(final String[] args) throws Exception {
System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "64"); // try to have parallelStream better than default
final File source = args == null || args.length < 1 ? new File("src/main/jbake") : new File(args[0]);
final File pdfSource = new File(source, "content");
final File destination = args == null || args.length < 2 ? new File("target/site-tmp") : new File(args[1]);
final boolean startHttp = args == null || args.length < 2 || Boolean.parseBoolean(args[2]); // by default we dev
final boolean skipPdf = args != null && args.length > 3 && !Boolean.parseBoolean(args[3]); // by default...too slow sorry
final boolean updateDownloads = args != null && args.length > 4 && Boolean.parseBoolean(args[4]); // grabs central
// generation of dynamic content
new Configuration().run();
new CliConfiguration().run();
new ArquillianConfiguration().run();
new MavenConfiguration().run();
new OAuth2Configuration().run();
new LetsEncryptConfiguration().run();
new GradleConfiguration().run();
new ProxyConfiguration().run();
if (updateDownloads) {
final ByteArrayOutputStream tableContent = new ByteArrayOutputStream();
try (final PrintStream stream = new PrintStream(tableContent)) {
Downloads.doMain(stream);
}
try (final Writer writer = new FileWriter(new File(source, "content/download.adoc"))) {
writer.write("= Downloads\n"
+ ":jbake-generated: true\n"
+ ":jbake-date: 2017-07-24\n"
+ ":jbake-type: page\n"
+ ":jbake-status: published\n"
+ ":jbake-meecrowavepdf:\n"
+ ":jbake-meecrowavecolor: body-blue\n"
+ ":icons: font\n"
+ "\n"
+ "License under Apache License v2 (ALv2).\n"
+ "\n"
+ "[.table.table-bordered,options=\"header\"]\n"
+ "|===\n"
+ "|Name|Version|Date|Size|Type|Links\n");
writer.write(new String(tableContent.toByteArray(), StandardCharsets.UTF_8));
writer.write("\n|===\n");
}
}
final Runnable build = () -> {
System.out.println("Building Meecrowave website in " + destination);
final Orient orient = Orient.instance();
try {
orient.startup();
final Oven oven = new Oven(source, destination, new CompositeConfiguration() {{
final CompositeConfiguration config = new CompositeConfiguration();
config.addConfiguration(new MapConfiguration(new HashMap<String, Object>() {{
put("asciidoctor.attributes", new ArrayList<String>() {{
add("source-highlighter=highlightjs");
add("highlightjs-theme=idea");
add("context_rootpath=/meecrowave");
}});
}}));
config.addConfiguration(DefaultJBakeConfiguration.class.cast(
new ConfigUtil().loadConfig(source)).getCompositeConfiguration());
addConfiguration(config);
}}, true);
oven.setupPaths();
System.out.println(" > baking");
oven.bake();
if (!skipPdf) {
System.out.println(" > pdfifying");
PDFify.generatePdf(pdfSource, destination);
}
System.out.println(" > done :)");
} catch (final Exception e) {
e.printStackTrace();
} finally {
orient.shutdown();
}
};
build.run();
if (startHttp) {
final Path watched = source.toPath();
final WatchService watchService = watched.getFileSystem().newWatchService();
watched.register(watchService, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
final AtomicBoolean run = new AtomicBoolean(true);
final AtomicLong render = new AtomicLong(-1);
final Thread renderingThread = new Thread() {
{
setName("jbake-renderer");
}
@Override
public void run() {
long last = System.currentTimeMillis();
while (run.get()) {
if (render.get() > last) {
last = System.currentTimeMillis();
try {
build.run();
} catch (final Throwable oops) {
oops.printStackTrace();
}
}
try {
sleep(TimeUnit.SECONDS.toMillis(1));
} catch (final InterruptedException e) {
Thread.interrupted();
break;
}
}
System.out.println("Exiting renderer");
}
};
final Thread watcherThread = new Thread() {
{
setName("jbake-file-watcher");
}
@Override
public void run() {
while (run.get()) {
try {
final WatchKey key = watchService.poll(1, TimeUnit.SECONDS);
if (key == null) {
continue;
}
for (final WatchEvent<?> event : key.pollEvents()) {
final WatchEvent.Kind<?> kind = event.kind();
if (kind != ENTRY_CREATE && kind != ENTRY_DELETE && kind != ENTRY_MODIFY) {
continue; // unlikely but better to protect ourself
}
final Path updatedPath = Path.class.cast(event.context());
if (kind == ENTRY_DELETE || updatedPath.toFile().isFile()) {
final String path = updatedPath.toString();
if (!path.contains("___jb") && !path.endsWith("~")) {
render.set(System.currentTimeMillis());
}
}
}
key.reset();
} catch (final InterruptedException e) {
Thread.interrupted();
run.compareAndSet(true, false);
} catch (final ClosedWatchServiceException cwse) {
if (!run.get()) {
throw new IllegalStateException(cwse);
}
}
}
System.out.println("Exiting file watcher");
}
};
renderingThread.start();
watcherThread.start();
final Runnable onQuit = () -> {
run.compareAndSet(true, false);
Stream.of(watcherThread, renderingThread).forEach(thread -> {
try {
thread.join();
} catch (final InterruptedException e) {
Thread.interrupted();
}
});
try {
watchService.close();
} catch (final IOException ioe) {
// not important
}
};
try (final Meecrowave container = new Meecrowave(new Meecrowave.Builder() {{
setWebResourceCached(false);
}}) {{
start();
deployWebapp("/meecrowave", destination);
}}) {
System.out.println("Started on http://localhost:" + container.getConfiguration().getHttpPort() + "/meecrowave");
final Scanner console = new Scanner(System.in);
String cmd;
while (((cmd = console.nextLine())) != null) {
if ("quit".equals(cmd)) {
break;
} else if ("r".equals(cmd) || "rebuild".equals(cmd) || "build".equals(cmd) || "b".equals(cmd)) {
render.set(System.currentTimeMillis());
} else {
System.err.println("Ignoring " + cmd + ", please use 'build' or 'quit'");
}
}
}
onQuit.run();
}
}
}