Skip to content

Commit

Permalink
Merge pull request #572 from ancho/feature/picocli-integration
Browse files Browse the repository at this point in the history
switch to picocli
  • Loading branch information
jonbullock committed May 20, 2021
2 parents df55d33 + 96156b0 commit dcc0e83
Show file tree
Hide file tree
Showing 13 changed files with 176 additions and 143 deletions.
2 changes: 2 additions & 0 deletions gradle.properties
Expand Up @@ -28,6 +28,8 @@ pebbleVersion = 3.1.5
slf4jVersion = 1.7.30
snakeYamlVersion = 1.28
thymeleafVersion = 3.0.12.RELEASE
picocli = 4.6.1


# testing dependencies
junit4Version = 4.13.2
Expand Down
2 changes: 1 addition & 1 deletion jbake-core/build.gradle
Expand Up @@ -30,7 +30,7 @@ dependencies {

// cli specific dependencies
implementation "org.eclipse.jetty:jetty-server:$jettyServerVersion", optional
implementation "args4j:args4j:$args4jVersion", optional
implementation "info.picocli:picocli:$picocli", optional
}

processResources {
Expand Down
3 changes: 2 additions & 1 deletion jbake-core/src/main/java/org/jbake/app/ContentStore.java
Expand Up @@ -36,6 +36,7 @@
import com.orientechnologies.orient.core.sql.OCommandSQL;
import com.orientechnologies.orient.core.sql.executor.OResultSet;
import com.orientechnologies.orient.core.sql.query.OSQLSynchQuery;
import org.jbake.launcher.SystemExit;
import org.jbake.model.DocumentAttributes;
import org.jbake.model.DocumentTypes;
import org.slf4j.Logger;
Expand Down Expand Up @@ -212,7 +213,7 @@ public ODocument mergeDocument(Map<String, ? extends Object> incomingDocMap) {
activateOnCurrentThread();
List<ODocument> results = db.command(new OSQLSynchQuery<ODocument>(sql)).execute(sourceUri);
if (results.isEmpty()) {
throw new JBakeException("No document with sourceUri '" + sourceUri + "'.");
throw new JBakeException(SystemExit.ERROR, "No document with sourceUri '" + sourceUri + "'.");
}

// Update it from the given map.
Expand Down
16 changes: 13 additions & 3 deletions jbake-core/src/main/java/org/jbake/app/JBakeException.java
@@ -1,5 +1,7 @@
package org.jbake.app;

import org.jbake.launcher.SystemExit;

/**
* This runtime exception is thrown by JBake API to indicate an processing
* error.
Expand All @@ -9,18 +11,26 @@
public class JBakeException extends RuntimeException {
private static final long serialVersionUID = 1L;

final private SystemExit exit;

/**
*
* @param message
* The error message.
* @param cause
* The causing exception or <code>null</code> if no cause
* available.
*/
public JBakeException(final String message, final Throwable cause) {
public JBakeException(final SystemExit exit, final String message, final Throwable cause) {
super(message, cause);
this.exit = exit;
}

public JBakeException(final SystemExit exit, final String message) {
this(exit, message, null);
}

public JBakeException(final String message) {
this(message, null);
public int getExit() {
return exit.getStatus();
}
}
Expand Up @@ -5,14 +5,12 @@
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.configuration.SystemConfiguration;
import org.jbake.app.JBakeException;
import org.jbake.launcher.SystemExit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.charset.Charset;

/**
* Provides Configuration related functions.
Expand All @@ -29,10 +27,10 @@ public class ConfigUtil {
private CompositeConfiguration load(File source) throws ConfigurationException {

if (!source.exists()) {
throw new JBakeException("The given source folder '" + source.getAbsolutePath() + "' does not exist.");
throw new JBakeException(SystemExit.CONFIGURATION_ERROR, "The given source folder '" + source.getAbsolutePath() + "' does not exist.");
}
if (!source.isDirectory()) {
throw new JBakeException("The given source folder is not a directory.");
throw new JBakeException(SystemExit.CONFIGURATION_ERROR,"The given source folder is not a directory.");
}
CompositeConfiguration config = new CompositeConfiguration();
config.setListDelimiter(',');
Expand Down
Expand Up @@ -2,6 +2,7 @@

import org.jbake.app.FileUtil;
import org.jbake.app.JBakeException;
import org.jbake.launcher.SystemExit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -28,10 +29,10 @@ public void inspect() throws JBakeException {
private void ensureSource() throws JBakeException {
File source = configuration.getSourceFolder();
if (!FileUtil.isExistingFolder(source)) {
throw new JBakeException("Error: Source folder must exist: " + source.getAbsolutePath());
throw new JBakeException(SystemExit.CONFIGURATION_ERROR, "Error: Source folder must exist: " + source.getAbsolutePath());
}
if (!configuration.getSourceFolder().canRead()) {
throw new JBakeException("Error: Source folder is not readable: " + source.getAbsolutePath());
throw new JBakeException(SystemExit.CONFIGURATION_ERROR, "Error: Source folder is not readable: " + source.getAbsolutePath());
}
}

Expand All @@ -51,7 +52,7 @@ private void ensureDestination() {
destination.mkdirs();
}
if (!destination.canWrite()) {
throw new JBakeException("Error: Destination folder is not writable: " + destination.getAbsolutePath());
throw new JBakeException(SystemExit.CONFIGURATION_ERROR, "Error: Destination folder is not writable: " + destination.getAbsolutePath());
}
}

Expand All @@ -62,9 +63,9 @@ private void checkAssetFolder() {
}
}

private void checkRequiredFolderExists(String property, File path) {
private void checkRequiredFolderExists(String folderName, File path) {
if (!FileUtil.isExistingFolder(path)) {
throw new JBakeException("Error: Required folder cannot be found! Expected to find [" + property + "] at: " + path.getAbsolutePath());
throw new JBakeException(SystemExit.CONFIGURATION_ERROR, "Error: Required folder cannot be found! Expected to find [" + folderName + "] at: " + path.getAbsolutePath());
}
}

Expand Down
2 changes: 1 addition & 1 deletion jbake-core/src/main/java/org/jbake/launcher/Baker.java
Expand Up @@ -41,7 +41,7 @@ public void bake(final JBakeConfiguration config) {
msg.append(MessageFormat.format("{0}. {1}\n", errNr, error.getMessage()));
++errNr;
}
throw new JBakeException(msg.toString(), errors.get(0));
throw new JBakeException(SystemExit.ERROR ,msg.toString(), errors.get(0));
}
}
}
42 changes: 22 additions & 20 deletions jbake-core/src/main/java/org/jbake/launcher/JettyServer.java
Expand Up @@ -7,6 +7,7 @@
import org.eclipse.jetty.server.handler.DefaultHandler;
import org.eclipse.jetty.server.handler.HandlerList;
import org.eclipse.jetty.server.handler.ResourceHandler;
import org.jbake.app.JBakeException;
import org.jbake.app.configuration.JBakeConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -34,41 +35,42 @@ public void run(String resourceBase, String port) {
public void run(String resourceBase, JBakeConfiguration configuration) {
run(resourceBase, configuration.getServerContextPath(), configuration.getServerHostname(), configuration.getServerPort());
}

/**
* Run Jetty web server serving out supplied path on supplied port
*
* @param resourceBase Base directory for resources to be served
* @param port Required server port
* @param port Required server port
*/
private void run(String resourceBase, String contextPath, String hostname, int port) {
server = new Server();
ServerConnector connector = new ServerConnector(server);
connector.setHost(hostname);
connector.setPort(port);
server.addConnector(connector);
try {
server = new Server();
ServerConnector connector = new ServerConnector(server);
connector.setHost(hostname);
connector.setPort(port);
server.addConnector(connector);

ResourceHandler resource_handler = new ResourceHandler();
resource_handler.setDirectoriesListed(true);
resource_handler.setWelcomeFiles(new String[]{"index", "index.html"});
resource_handler.setResourceBase(resourceBase);
ResourceHandler resource_handler = new ResourceHandler();
resource_handler.setDirectoriesListed(true);
resource_handler.setWelcomeFiles(new String[]{"index", "index.html"});
resource_handler.setResourceBase(resourceBase);

ContextHandler contextHandler = new ContextHandler();
contextHandler.setContextPath(contextPath);
contextHandler.setHandler(resource_handler);
ContextHandler contextHandler = new ContextHandler();
contextHandler.setContextPath(contextPath);
contextHandler.setHandler(resource_handler);

HandlerList handlers = new HandlerList();
HandlerList handlers = new HandlerList();

handlers.setHandlers(new Handler[]{contextHandler, new DefaultHandler()});
server.setHandler(handlers);
handlers.setHandlers(new Handler[]{contextHandler, new DefaultHandler()});
server.setHandler(handlers);

LOGGER.info("Serving out contents of: [{}] on http://{}:{}{}", resourceBase, hostname, port, contextHandler.getContextPath());
LOGGER.info("(To stop server hit CTRL-C)");
LOGGER.info("Serving out contents of: [{}] on http://{}:{}{}", resourceBase, hostname, port, contextHandler.getContextPath());
LOGGER.info("(To stop server hit CTRL-C)");

try {
server.start();
server.join();
} catch (Exception e) {
LOGGER.error("unable to start server", e);
throw new JBakeException(SystemExit.SERVER_ERROR, "unable to start the server", e);
}
}

Expand Down
49 changes: 29 additions & 20 deletions jbake-core/src/main/java/org/jbake/launcher/LaunchOptions.java
@@ -1,41 +1,50 @@
package org.jbake.launcher;

import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.Option;
import picocli.CommandLine.ArgGroup;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
import picocli.CommandLine.Parameters;

import java.io.File;

@Command(
description = "JBake is a Java based, open source, static site/blog generator for developers & designers",
name = "jbake",
usageHelpAutoWidth = true
)
public class LaunchOptions {
@Argument(index = 0, usage = "source folder of site content (with templates and assets), if not supplied will default to current directory", metaVar = "<source>")
@Parameters(index = "0", description = "source folder of site content (with templates and assets), if not supplied will default to current directory", arity = "0..1")
private String source;

@Argument(index = 1, usage = "destination folder for output, if not supplied will default to a folder called \"output\" in the current directory", metaVar = "<destination>")
@Parameters(index = "1", description = "destination folder for output, if not supplied will default to a folder called \"output\" in the current directory", arity = "0..1")
private String destination;

@Option(name = "-b", aliases = {"--bake"}, usage = "performs a bake")
@Option(names = {"-b", "--bake"}, description = "performs a bake")
private boolean bake;

@Option(name = "-i", aliases = {"--init"}, usage = "initialises required folder structure with default templates (defaults to current directory if <value> is not supplied)")
private boolean init;
@ArgGroup(exclusive = false, heading = "%n%nJBake initialization%n%n")
private InitOptions initGroup;

@Option(name = "-t", aliases = {"--template"}, usage = "use specified template engine for default templates (uses Freemarker if <value> is not supplied) ", depends = ("-i"))
private String template;
static class InitOptions {

@Option(name = "-s", aliases = {"--server"}, usage = "runs HTTP server to serve out baked site, if no <value> is supplied will default to a folder called \"output\" in the current directory")
@Option(names = {"-i", "--init"}, paramLabel = "<target>", description = "initialises required folder structure with default templates (defaults to current directory if <source> is not supplied)", required = true)
private boolean init;

@Option(names = {"-t", "--template"}, defaultValue = "freemarker", fallbackValue = "freemarker", description = "use specified template engine for default templates (uses Freemarker if <template> is not supplied) ", arity = "0..1")
private String template;
}

@Option(names = {"-s", "--server"}, description = "runs HTTP server to serve out baked site, if no <value> is supplied will default to a folder called \"output\" in the current directory")
private boolean runServer;

@Option(name = "-h", aliases = {"--help"}, usage = "prints this message")
private boolean helpNeeded;
@Option(names = {"-h", "--help"}, description = "prints this message", usageHelp = true)
private boolean helpRequested;

@Option(name = "--reset", usage = "clears the local cache, enforcing rendering from scratch")
@Option(names = {"--reset"}, description = "clears the local cache, enforcing rendering from scratch")
private boolean clearCache;

public String getTemplate() {
if (template != null) {
return template;
} else {
return "freemarker";
}
return initGroup.template;
}

public File getSource() {
Expand Down Expand Up @@ -63,15 +72,15 @@ public String getDestinationValue() {
}

public boolean isHelpNeeded() {
return helpNeeded || !(isBake() || isRunServer() || isInit() || source != null || destination != null);
return helpRequested || !(isBake() || isRunServer() || isInit() || source != null || destination != null);
}

public boolean isRunServer() {
return runServer;
}

public boolean isInit() {
return init;
return (initGroup !=null && initGroup.init);
}

public boolean isClearCache() {
Expand Down

0 comments on commit dcc0e83

Please sign in to comment.