Skip to content

Commit

Permalink
Added support for generating bld output as JSON so that it can be con…
Browse files Browse the repository at this point in the history
…sumed by other tools.

Added wrapper support for local Maven repository bld snapshots.
Updated version to 2.0.0-SNAPSHOT.
  • Loading branch information
gbevin committed Jun 25, 2024
1 parent 177a2e3 commit 793efb2
Show file tree
Hide file tree
Showing 13 changed files with 294 additions and 89 deletions.
142 changes: 117 additions & 25 deletions src/main/java/rife/bld/BuildExecutor.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@
import rife.bld.operations.HelpOperation;
import rife.bld.operations.exceptions.ExitStatusException;
import rife.ioc.HierarchicalProperties;
import rife.template.Template;
import rife.template.TemplateFactory;
import rife.tools.ExceptionUtils;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Logger;
Expand All @@ -38,6 +39,7 @@ public class BuildExecutor {
private static final String ARG_HELP3 = "-?";
private static final String ARG_STACKTRACE1 = "--stacktrace";
private static final String ARG_STACKTRACE2 = "-s";
private static final String ARG_JSON = "--json";

private final HierarchicalProperties properties_;
private List<String> arguments_ = Collections.emptyList();
Expand All @@ -46,6 +48,7 @@ public class BuildExecutor {
private final AtomicReference<String> currentCommandName_ = new AtomicReference<>();
private final AtomicReference<CommandDefinition> currentCommandDefinition_ = new AtomicReference<>();
private int exitStatus_ = 0;
private boolean outputJson_ = false;

/**
* Show the full Java stacktrace when exceptions occur, as opposed
Expand Down Expand Up @@ -124,6 +127,17 @@ public static HierarchicalProperties setupProperties(File workDirectory) {
return properties;
}

/**
* Returns whether output should be in the JSON format.
*
* @return {@code true} if JSON output is enabled;
* or {@code false} otherwise
* @since 2.0.0
*/
public boolean outputJson() {
return outputJson_;
}

/**
* Returns the properties uses by this conversation.
*
Expand Down Expand Up @@ -213,51 +227,119 @@ public int exitStatus() {
public int execute(String[] arguments) {
arguments_ = new ArrayList<>(Arrays.asList(arguments));

if (!arguments_.isEmpty() && arguments_.get(0).equals(ARG_JSON)) {
outputJson_ = true;
arguments_.remove(0);
}
var show_help = false;
show_help |= arguments_.removeAll(List.of(ARG_HELP1, ARG_HELP2, ARG_HELP3));
showStacktrace |= arguments_.removeAll(List.of(ARG_STACKTRACE1, ARG_STACKTRACE2));
showStacktrace = arguments_.removeAll(List.of(ARG_STACKTRACE1, ARG_STACKTRACE2));
show_help |= arguments_.isEmpty();

if (show_help) {
new HelpOperation(this, Collections.emptyList()).execute();
return exitStatus_;
}

var first_command = true;
var json_template = TemplateFactory.JSON.get("bld.executor_execute");
var exception_caught = false;
while (!arguments_.isEmpty()) {
var command = arguments_.remove(0);

try {
if (!executeCommand(command)) {
break;
var orig_out = System.out;
var orig_err = System.err;
var out = new ByteArrayOutputStream();
var err = new ByteArrayOutputStream();
if (outputJson()) {
System.setOut(new PrintStream(out, true, StandardCharsets.UTF_8));
System.setErr(new PrintStream(err, true, StandardCharsets.UTF_8));
}

try {
if (!executeCommand(command)) {
break;
}
}
finally {
if (outputJson()) {
if (first_command) {
json_template.blankValue("separator");
}
else {
json_template.setValue("separator", ", ");
}
json_template.setValueEncoded("command", command);
json_template.setValueEncoded("out", out.toString(StandardCharsets.UTF_8));
json_template.setValueEncoded("err", err.toString(StandardCharsets.UTF_8));
json_template.appendBlock("commands", "command");

System.setOut(orig_out);
System.setErr(orig_err);
}

first_command = false;
}
} catch (Throwable e) {
exitStatus(1);
exception_caught = true;

System.err.println();
exitStatus(1);

if (showStacktrace) {
System.err.println(ExceptionUtils.getExceptionStackTrace(e));
} else {
boolean first = true;
var e2 = e;
while (e2 != null) {
if (e2.getMessage() != null) {
if (!first) {
System.err.print("> ");
if (outputJson()) {
var t = TemplateFactory.JSON.get("bld.executor_error");
if (showStacktrace) {
t.setValueEncoded("error-message", ExceptionUtils.getExceptionStackTrace(e));
}
else {
boolean first_exception = true;
var e2 = e;
while (e2 != null) {
if (e2.getMessage() != null) {
t.setValueEncoded("error-message", e2.getMessage());
first_exception = false;
}
System.err.println(e2.getMessage());
first = false;
e2 = e2.getCause();
}

if (first_exception) {
t.setValueEncoded("error-message", ExceptionUtils.getExceptionStackTrace(e));
}
e2 = e2.getCause();
}
System.out.println(t.getContent());
}
else {
System.err.println();

if (first) {
if (showStacktrace) {
System.err.println(ExceptionUtils.getExceptionStackTrace(e));
} else {
boolean first_exception = true;
var e2 = e;
while (e2 != null) {
if (e2.getMessage() != null) {
if (!first_exception) {
System.err.print("> ");
}
System.err.println(e2.getMessage());
first_exception = false;
}
e2 = e2.getCause();
}

if (first_exception) {
System.err.println(ExceptionUtils.getExceptionStackTrace(e));
}
}
}
}
}

if (!exception_caught) {
if (outputJson()) {
System.out.println(json_template.getContent());
}
}

return exitStatus_;
}
Expand Down Expand Up @@ -441,7 +523,9 @@ public boolean executeCommand(String command)
// only proceed if exactly one match was found
if (matches.size() == 1) {
matched_command = matches.get(0);
System.out.println("Executing matched command: " + matched_command);
if (!outputJson()) {
System.out.println("Executing matched command: " + matched_command);
}
definition = buildCommands().get(matched_command);
}
}
Expand All @@ -460,9 +544,17 @@ public boolean executeCommand(String command)
currentCommandName_.set(null);
}
} else {
new HelpOperation(this, arguments()).executePrintOverviewHelp();
System.err.println();
System.err.println("ERROR: unknown command '" + command + "'");
var message = "Unknown command '" + command + "'";
if (outputJson()) {
var t = TemplateFactory.JSON.get("bld.executor_error");
t.setValueEncoded("error-message", message);
System.out.println(t.getContent());
}
else {
new HelpOperation(this, arguments()).executePrintOverviewHelp();
System.err.println();
System.err.println("ERROR: " + message);
}
exitStatus(1);
return false;
}
Expand Down
1 change: 1 addition & 0 deletions src/main/java/rife/bld/operations/DownloadOperation.java
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ protected void executeDownloadDependencies(File destinationDirectory, Dependency
* Configures a compile operation from a {@link BaseProject}.
*
* @param project the project to configure the compile operation from
* @return this operation instance
* @since 1.5
*/
public DownloadOperation fromProject(BaseProject project) {
Expand Down
104 changes: 76 additions & 28 deletions src/main/java/rife/bld/operations/HelpOperation.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

import rife.bld.BldVersion;
import rife.bld.BuildExecutor;
import rife.template.TemplateFactory;
import rife.tools.ExceptionUtils;

import java.util.List;

Expand Down Expand Up @@ -44,26 +46,37 @@ public void execute() {
topic = arguments_.remove(0);
}

System.err.println("Welcome to bld " + BldVersion.getVersion() + ".");
System.err.println();
if (!executor_.outputJson()) {
System.err.println("Welcome to bld " + BldVersion.getVersion() + ".");
System.err.println();
}

boolean print_full_help = true;
Exception exception = null;
try {
var commands = executor_.buildCommands();
if (commands.containsKey(topic)) {
var command = commands.get(topic);
var help = command.getHelp().getDescription(topic);
if (!help.isEmpty()) {
System.err.println(help);
if (executor_.outputJson()) {
var t = TemplateFactory.JSON.get("bld.help_description");
t.setValueEncoded("command", topic);
t.setValueEncoded("description", help);
System.out.print(t.getContent());
}
else {
System.err.println(help);
}
print_full_help = false;
}
}
} catch (Exception e) {
e.printStackTrace();
exception = e;
}

if (print_full_help) {
executePrintOverviewHelp();
executePrintOverviewHelp(exception);
}
}

Expand All @@ -74,32 +87,67 @@ public void execute() {
* @since 1.5
*/
public void executePrintOverviewHelp() {
executePrintOverviewHelp(null);
}

private void executePrintOverviewHelp(Exception exception) {
var commands = executor_.buildCommands();

System.err.println("""
The bld CLI provides its features through a series of commands that
perform specific tasks. The help command provides more information about
the other commands.
Usage: help [command]
The following commands are supported.
""");

var command_length = commands.keySet().stream().max(comparingInt(String::length)).get().length() + 2;
for (var command : commands.entrySet()) {
System.err.print(" ");
System.err.printf("%-" + command_length + "s", command.getKey());
var build_help = command.getValue().getHelp();
System.err.print(build_help.getSummary());
System.err.println();
if (executor_.outputJson()) {
var t = TemplateFactory.JSON.get("bld.help_commands");

if (exception != null) {
t.setValueEncoded("error-message", ExceptionUtils.getExceptionStackTrace(exception));
}

boolean first = true;
for (var command : commands.entrySet()) {
if (first) {
first = false;
t.blankValue("separator");
}
else {
t.setValue("separator", ", ");
}
t.setValueEncoded("command", command.getKey());
var build_help = command.getValue().getHelp();
t.setValueEncoded("summary", build_help.getSummary());
t.appendBlock("commands", "command");
}
System.out.print(t.getContent());

}
else {
if (exception != null) {
exception.printStackTrace();
}

System.err.println("""
-?, -h, --help Shows this help message
-D<name>=<value> Set a JVM system property
-s, --stacktrace Print out the stacktrace for exceptions
""");
System.err.println("""
The bld CLI provides its features through a series of commands that
perform specific tasks. The help command provides more information about
the other commands.
Usage: help [command]
The following commands are supported.
""");

var command_length = commands.keySet().stream().max(comparingInt(String::length)).get().length() + 2;
for (var command : commands.entrySet()) {
System.err.print(" ");
System.err.printf("%-" + command_length + "s", command.getKey());
var build_help = command.getValue().getHelp();
System.err.print(build_help.getSummary());
System.err.println();
}

System.err.println("""
-?, -h, --help Shows this help message
-D<name>=<value> Set a JVM system property
-s, --stacktrace Print out the stacktrace for exceptions
--json Output in JSON format (only as first argument)
""");
}
}
}
4 changes: 2 additions & 2 deletions src/main/java/rife/bld/operations/PublishOperation.java
Original file line number Diff line number Diff line change
Expand Up @@ -604,7 +604,7 @@ public PublishOperation dependencies(DependencyScopes dependencies) {
*
* @param properties the publication properties
* @return this operation instance
* @since 1.9.2
* @since 2.0.0
*/
public PublishOperation properties(PublishProperties properties) {
properties_ = properties;
Expand Down Expand Up @@ -691,7 +691,7 @@ public DependencyScopes dependencies() {
* This is a modifiable structure that can be retrieved and changed.
*
* @return the publication properties
* @since 1.9.2
* @since 2.0.0
*/
public PublishProperties properties() {
return properties_;
Expand Down
Loading

0 comments on commit 793efb2

Please sign in to comment.