mirror of
https://github.com/apache/maven-mvnd.git
synced 2025-09-25 13:46:30 +00:00
mvnd should fail cleanly with unknown CLI options, fixes #11
This commit is contained in:
@@ -30,8 +30,10 @@ import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.apache.commons.cli.UnrecognizedOptionException;
|
||||
import org.apache.maven.cli.CLIReportingUtils;
|
||||
import org.jboss.fuse.mvnd.daemon.Message.BuildEvent;
|
||||
import org.jboss.fuse.mvnd.daemon.Message.BuildException;
|
||||
import org.jboss.fuse.mvnd.daemon.Message.BuildMessage;
|
||||
import org.jboss.fuse.mvnd.daemon.Message.MessageSerializer;
|
||||
import org.jboss.fuse.mvnd.jpm.Process;
|
||||
@@ -41,6 +43,8 @@ import org.jline.terminal.Size;
|
||||
import org.jline.terminal.Terminal;
|
||||
import org.jline.terminal.TerminalBuilder;
|
||||
import org.jline.utils.AttributedString;
|
||||
import org.jline.utils.AttributedStringBuilder;
|
||||
import org.jline.utils.AttributedStyle;
|
||||
import org.jline.utils.Display;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -57,7 +61,7 @@ public class Client {
|
||||
List<String> args = new ArrayList<>(Arrays.asList(argv));
|
||||
|
||||
// Print version if needed
|
||||
boolean version = args.remove("-v") || args.remove("--version");
|
||||
boolean version = args.remove("-v") || args.remove("-version") || args.remove("--version");
|
||||
boolean showVersion = args.contains("-V") || args.contains("--show-version");
|
||||
boolean debug = args.contains("-X") || args.contains("--debug");
|
||||
if (version || showVersion || debug) {
|
||||
@@ -134,9 +138,13 @@ public class Client {
|
||||
Terminal terminal = TerminalBuilder.terminal();
|
||||
Display display = new Display(terminal, false);
|
||||
boolean exit = false;
|
||||
BuildException error = null;
|
||||
while (!exit) {
|
||||
Message m = daemon.receive();
|
||||
if (m instanceof BuildEvent) {
|
||||
if (m instanceof BuildException) {
|
||||
error = (BuildException) m;
|
||||
exit = true;
|
||||
} else if (m instanceof BuildEvent) {
|
||||
BuildEvent be = (BuildEvent) m;
|
||||
switch (be.getType()) {
|
||||
case BuildStarted:
|
||||
@@ -167,6 +175,16 @@ public class Client {
|
||||
}
|
||||
}
|
||||
display.update(Collections.emptyList(), 0);
|
||||
if (error != null) {
|
||||
AttributedStyle s = new AttributedStyle().bold().foreground(AttributedStyle.RED);
|
||||
String msg;
|
||||
if (UnrecognizedOptionException.class.getName().equals(error.getClassName())) {
|
||||
msg = "Unable to parse command line options: " + error.getMessage();
|
||||
} else {
|
||||
msg = error.getClassName() + ": " + error.getMessage();
|
||||
}
|
||||
terminal.writer().println(new AttributedString(msg, s).toAnsi());
|
||||
}
|
||||
terminal.flush();
|
||||
|
||||
LOGGER.debug("Done receiving, printing log");
|
||||
|
@@ -23,6 +23,8 @@ import java.io.UTFDataFormatException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.codehaus.plexus.util.ExceptionUtils;
|
||||
|
||||
public abstract class Message {
|
||||
|
||||
final long timestamp = System.nanoTime();
|
||||
@@ -53,6 +55,52 @@ public abstract class Message {
|
||||
public String getProjectDir() {
|
||||
return projectDir;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "BuildRequest{" +
|
||||
"args=" + args +
|
||||
", workingDir='" + workingDir + '\'' +
|
||||
", projectDir='" + projectDir + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
public static class BuildException extends Message {
|
||||
final String message;
|
||||
final String className;
|
||||
final String stackTrace;
|
||||
|
||||
public BuildException(Throwable t) {
|
||||
this(t.getMessage(), t.getClass().getName(), ExceptionUtils.getStackTrace(t));
|
||||
}
|
||||
|
||||
public BuildException(String message, String className, String stackTrace) {
|
||||
this.message = message;
|
||||
this.className = className;
|
||||
this.stackTrace = stackTrace;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public String getClassName() {
|
||||
return className;
|
||||
}
|
||||
|
||||
public String getStackTrace() {
|
||||
return stackTrace;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "BuildException{" +
|
||||
"message='" + message + '\'' +
|
||||
", className='" + className + '\'' +
|
||||
", stackTrace='" + stackTrace + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
public static class BuildEvent extends Message {
|
||||
@@ -114,6 +162,7 @@ public abstract class Message {
|
||||
final int BUILD_REQUEST = 0;
|
||||
final int BUILD_EVENT = 1;
|
||||
final int BUILD_MESSAGE = 2;
|
||||
final int BUILD_EXCEPTION = 3;
|
||||
|
||||
@Override
|
||||
public Message read(DataInputStream input) throws EOFException, Exception {
|
||||
@@ -128,6 +177,8 @@ public abstract class Message {
|
||||
return readBuildEvent(input);
|
||||
case BUILD_MESSAGE:
|
||||
return readBuildMessage(input);
|
||||
case BUILD_EXCEPTION:
|
||||
return readBuildException(input);
|
||||
}
|
||||
throw new IllegalStateException("Unexpected message type: " + type);
|
||||
}
|
||||
@@ -143,6 +194,9 @@ public abstract class Message {
|
||||
} else if (value instanceof BuildMessage) {
|
||||
output.write(BUILD_MESSAGE);
|
||||
writeBuildMessage(output, (BuildMessage) value);
|
||||
} else if (value instanceof BuildException) {
|
||||
output.write(BUILD_EXCEPTION);
|
||||
writeBuildException(output, (BuildException) value);
|
||||
} else {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
@@ -183,6 +237,19 @@ public abstract class Message {
|
||||
writeUTF(output, value.message);
|
||||
}
|
||||
|
||||
private BuildException readBuildException(DataInputStream input) throws IOException {
|
||||
String message = readUTF(input);
|
||||
String className = readUTF(input);
|
||||
String stackTrace = readUTF(input);
|
||||
return new BuildException(message, className, stackTrace);
|
||||
}
|
||||
|
||||
private void writeBuildException(DataOutputStream output, BuildException value) throws IOException {
|
||||
writeUTF(output, value.message);
|
||||
writeUTF(output, value.className);
|
||||
writeUTF(output, value.stackTrace);
|
||||
}
|
||||
|
||||
private List<String> readStringList(DataInputStream input) throws IOException {
|
||||
ArrayList<String> l = new ArrayList<>();
|
||||
int nb = input.readInt();
|
||||
|
@@ -42,6 +42,7 @@ import org.jboss.fuse.mvnd.daemon.DaemonExpiration.DaemonExpirationStatus;
|
||||
import org.jboss.fuse.mvnd.daemon.DaemonExpiration.DaemonExpirationStrategy;
|
||||
import org.jboss.fuse.mvnd.daemon.Message.BuildEvent;
|
||||
import org.jboss.fuse.mvnd.daemon.Message.BuildEvent.Type;
|
||||
import org.jboss.fuse.mvnd.daemon.Message.BuildException;
|
||||
import org.jboss.fuse.mvnd.daemon.Message.BuildMessage;
|
||||
import org.jboss.fuse.mvnd.daemon.Message.BuildRequest;
|
||||
import org.jboss.fuse.mvnd.daemon.Message.MessageSerializer;
|
||||
@@ -386,48 +387,8 @@ public class Server implements AutoCloseable, Runnable {
|
||||
PriorityBlockingQueue<Message> queue = new PriorityBlockingQueue<Message>(64,
|
||||
Comparator.comparingInt(this::getClassOrder).thenComparingLong(Message::timestamp));
|
||||
|
||||
AbstractLoggingSpy.instance(new AbstractLoggingSpy() {
|
||||
@Override
|
||||
public void init(Context context) throws Exception {
|
||||
super.init(context);
|
||||
queue.add(new BuildEvent(Type.BuildStarted, "", ""));
|
||||
}
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
sendBuildMessages();
|
||||
queue.add(new BuildEvent(Type.BuildStopped, "", ""));
|
||||
queue.add(STOP);
|
||||
super.close();
|
||||
}
|
||||
@Override
|
||||
protected void onStartProject(ProjectBuild project) {
|
||||
sendEvent(Type.ProjectStarted, project);
|
||||
}
|
||||
@Override
|
||||
protected void onStopProject(ProjectBuild project) {
|
||||
sendEvent(Type.ProjectStopped, project);
|
||||
}
|
||||
@Override
|
||||
protected void onStartMojo(ProjectBuild project) {
|
||||
sendEvent(Type.MojoStarted, project);
|
||||
}
|
||||
@Override
|
||||
protected void onStopMojo(ProjectBuild project) {
|
||||
sendEvent(Type.MojoStopped, project);
|
||||
}
|
||||
private void sendEvent(Type type, ProjectBuild project) {
|
||||
String projectId = project.projectId();
|
||||
String disp = project.toDisplay().toAnsi(256, false);
|
||||
queue.add(new Message.BuildEvent(type, projectId, disp));
|
||||
sendBuildMessages();
|
||||
}
|
||||
private synchronized void sendBuildMessages() {
|
||||
events.stream()
|
||||
.map(s -> s.endsWith("\n") ? s.substring(0, s.length() - 1) : s)
|
||||
.map(Message.BuildMessage::new).forEachOrdered(queue::add);
|
||||
events.clear();
|
||||
}
|
||||
});
|
||||
DaemonLoggingSpy loggingSpy = new DaemonLoggingSpy(queue);
|
||||
AbstractLoggingSpy.instance(loggingSpy);
|
||||
Thread pumper = new Thread(() -> {
|
||||
try {
|
||||
while (true) {
|
||||
@@ -451,9 +412,16 @@ public class Server implements AutoCloseable, Runnable {
|
||||
}
|
||||
});
|
||||
pumper.start();
|
||||
cli.doMain(req);
|
||||
LOGGER.info("Build finished, finishing message dispatch");
|
||||
pumper.join();
|
||||
try {
|
||||
cli.doMain(req);
|
||||
LOGGER.info("Build finished, finishing message dispatch");
|
||||
loggingSpy.finish();
|
||||
} catch (Throwable t) {
|
||||
LOGGER.error("Error while building project", t);
|
||||
loggingSpy.fail(t);
|
||||
} finally {
|
||||
pumper.join();
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
LOGGER.error("Error while building project", t);
|
||||
} finally {
|
||||
@@ -470,6 +438,8 @@ public class Server implements AutoCloseable, Runnable {
|
||||
return be.getType() == Type.BuildStopped ? 98 : 1;
|
||||
} else if (m instanceof BuildMessage) {
|
||||
return 2;
|
||||
} else if (m instanceof BuildException) {
|
||||
return 97;
|
||||
} else if (m == STOP) {
|
||||
return 99;
|
||||
} else {
|
||||
@@ -517,4 +487,71 @@ public class Server implements AutoCloseable, Runnable {
|
||||
public long getLastBusy() {
|
||||
return info.getLastBusy();
|
||||
}
|
||||
|
||||
private static class DaemonLoggingSpy extends AbstractLoggingSpy {
|
||||
private final PriorityBlockingQueue<Message> queue;
|
||||
|
||||
public DaemonLoggingSpy(PriorityBlockingQueue<Message> queue) {
|
||||
this.queue = queue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Context context) throws Exception {
|
||||
super.init(context);
|
||||
queue.add(new BuildEvent(Type.BuildStarted, "", ""));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
LOGGER.error("Closing spy", new Throwable());
|
||||
sendBuildMessages();
|
||||
super.close();
|
||||
}
|
||||
|
||||
public void finish() throws Exception {
|
||||
queue.add(new BuildEvent(Type.BuildStopped, "", ""));
|
||||
queue.add(STOP);
|
||||
}
|
||||
|
||||
public void fail(Throwable t) throws Exception {
|
||||
queue.add(new BuildException(t));
|
||||
queue.add(STOP);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStartProject(ProjectBuild project) {
|
||||
sendEvent(Type.ProjectStarted, project);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStopProject(ProjectBuild project) {
|
||||
sendEvent(Type.ProjectStopped, project);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStartMojo(ProjectBuild project) {
|
||||
sendEvent(Type.MojoStarted, project);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStopMojo(ProjectBuild project) {
|
||||
sendEvent(Type.MojoStopped, project);
|
||||
}
|
||||
|
||||
private void sendEvent(Type type, ProjectBuild project) {
|
||||
String projectId = project.projectId();
|
||||
String disp = project.toDisplay().toAnsi(256, false);
|
||||
queue.add(new BuildEvent(type, projectId, disp));
|
||||
sendBuildMessages();
|
||||
}
|
||||
|
||||
private synchronized void sendBuildMessages() {
|
||||
if (events != null) {
|
||||
events.stream()
|
||||
.map(s -> s.endsWith("\n") ? s.substring(0, s.length() - 1) : s)
|
||||
.map(BuildMessage::new).forEachOrdered(queue::add);
|
||||
events.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user