mirror of
https://github.com/apache/maven-mvnd.git
synced 2025-09-10 13:15:27 +00:00
Provide smarter output on the client, fixes #77
All events are directly forwarded to the client. The client is now responsible for ordering them per project and displaying them if needed. A thread is now started to read the terminal input with support for '+' to display one more line per project, '-' to display one line less, and 'Ctrl+L' to redraw the display which could become messed if the build messages are a bit unusual (this may require a better fix though).
This commit is contained in:
@@ -16,25 +16,28 @@
|
|||||||
package org.jboss.fuse.mvnd.client;
|
package org.jboss.fuse.mvnd.client;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InterruptedIOException;
|
||||||
import java.io.Writer;
|
import java.io.Writer;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.AbstractMap;
|
import java.util.ArrayDeque;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.Deque;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Map.Entry;
|
|
||||||
import java.util.concurrent.BlockingQueue;
|
import java.util.concurrent.BlockingQueue;
|
||||||
import java.util.concurrent.LinkedBlockingDeque;
|
import java.util.concurrent.LinkedBlockingDeque;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
import java.util.stream.Collector;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
import org.jboss.fuse.mvnd.common.Message.BuildException;
|
import org.jboss.fuse.mvnd.common.Message.BuildException;
|
||||||
import org.jline.terminal.Size;
|
import org.jline.terminal.Size;
|
||||||
import org.jline.terminal.Terminal;
|
import org.jline.terminal.Terminal;
|
||||||
import org.jline.terminal.TerminalBuilder;
|
import org.jline.terminal.TerminalBuilder;
|
||||||
import org.jline.utils.AttributedString;
|
import org.jline.utils.AttributedString;
|
||||||
|
import org.jline.utils.AttributedStringBuilder;
|
||||||
import org.jline.utils.AttributedStyle;
|
import org.jline.utils.AttributedStyle;
|
||||||
import org.jline.utils.Display;
|
import org.jline.utils.Display;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@@ -43,24 +46,50 @@ import org.slf4j.LoggerFactory;
|
|||||||
/**
|
/**
|
||||||
* A sink for various kinds of events sent by the daemon.
|
* A sink for various kinds of events sent by the daemon.
|
||||||
*/
|
*/
|
||||||
public interface ClientOutput extends AutoCloseable, Consumer<String> {
|
public interface ClientOutput extends AutoCloseable {
|
||||||
|
|
||||||
|
int CTRL_L = 'L' & 0x1f;
|
||||||
|
|
||||||
public void projectStateChanged(String projectId, String display);
|
public void projectStateChanged(String projectId, String display);
|
||||||
|
|
||||||
public void projectFinished(String projectId);
|
public void projectFinished(String projectId);
|
||||||
|
|
||||||
/** Receive a log message */
|
public void accept(String projectId, String message);
|
||||||
public void accept(String message);
|
|
||||||
|
|
||||||
public void error(BuildException m);
|
public void error(BuildException m);
|
||||||
|
|
||||||
|
enum EventType {
|
||||||
|
PROJECT_STATUS,
|
||||||
|
LOG,
|
||||||
|
ERROR,
|
||||||
|
END_OF_STREAM,
|
||||||
|
INPUT
|
||||||
|
}
|
||||||
|
|
||||||
|
class Event {
|
||||||
|
public final EventType type;
|
||||||
|
public final String projectId;
|
||||||
|
public final String message;
|
||||||
|
|
||||||
|
public Event(EventType type, String projectId, String message) {
|
||||||
|
this.type = type;
|
||||||
|
this.projectId = projectId;
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Project {
|
||||||
|
String status;
|
||||||
|
final List<String> log = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A terminal {@link ClientOutput} based on JLine.
|
* A terminal {@link ClientOutput} based on JLine.
|
||||||
*/
|
*/
|
||||||
static class TerminalOutput implements ClientOutput {
|
static class TerminalOutput implements ClientOutput {
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(TerminalOutput.class);
|
private static final Logger LOGGER = LoggerFactory.getLogger(TerminalOutput.class);
|
||||||
private final TerminalUpdater updater;
|
private final TerminalUpdater updater;
|
||||||
private final BlockingQueue<Map.Entry<String, String>> queue;
|
private final BlockingQueue<Event> queue;
|
||||||
|
|
||||||
public TerminalOutput(Path logFile) throws IOException {
|
public TerminalOutput(Path logFile) throws IOException {
|
||||||
this.queue = new LinkedBlockingDeque<>();
|
this.queue = new LinkedBlockingDeque<>();
|
||||||
@@ -69,7 +98,7 @@ public interface ClientOutput extends AutoCloseable, Consumer<String> {
|
|||||||
|
|
||||||
public void projectStateChanged(String projectId, String task) {
|
public void projectStateChanged(String projectId, String task) {
|
||||||
try {
|
try {
|
||||||
queue.put(new AbstractMap.SimpleImmutableEntry<>(projectId, task));
|
queue.put(new Event(EventType.PROJECT_STATUS, projectId, task));
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
}
|
}
|
||||||
@@ -77,16 +106,16 @@ public interface ClientOutput extends AutoCloseable, Consumer<String> {
|
|||||||
|
|
||||||
public void projectFinished(String projectId) {
|
public void projectFinished(String projectId) {
|
||||||
try {
|
try {
|
||||||
queue.put(new AbstractMap.SimpleImmutableEntry<>(projectId, null));
|
queue.put(new Event(EventType.PROJECT_STATUS, projectId, null));
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void accept(String message) {
|
public void accept(String projectId, String message) {
|
||||||
try {
|
try {
|
||||||
queue.put(new AbstractMap.SimpleImmutableEntry<>(TerminalUpdater.LOG, message));
|
queue.put(new Event(EventType.LOG, projectId, message));
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
}
|
}
|
||||||
@@ -106,27 +135,28 @@ public interface ClientOutput extends AutoCloseable, Consumer<String> {
|
|||||||
msg = error.getClassName() + ": " + error.getMessage();
|
msg = error.getClassName() + ": " + error.getMessage();
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
queue.put(new AbstractMap.SimpleImmutableEntry<>(TerminalUpdater.ERROR, msg));
|
queue.put(new Event(EventType.ERROR, null, msg));
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static class TerminalUpdater implements AutoCloseable {
|
static class TerminalUpdater implements AutoCloseable {
|
||||||
private static final String LOG = "<log>";
|
private final BlockingQueue<Event> queue;
|
||||||
private static final String ERROR = "<error>";
|
|
||||||
private static final String END_OF_STREAM = "<eos>";
|
|
||||||
private final BlockingQueue<Map.Entry<String, String>> queue;
|
|
||||||
private final Terminal terminal;
|
private final Terminal terminal;
|
||||||
private final Display display;
|
private final Display display;
|
||||||
private final LinkedHashMap<String, String> projects = new LinkedHashMap<>();
|
private final LinkedHashMap<String, Project> projects = new LinkedHashMap<>();
|
||||||
private final Log log;
|
private final Log log;
|
||||||
private final Thread worker;
|
private final Thread worker;
|
||||||
|
private final Thread reader;
|
||||||
private volatile Exception exception;
|
private volatile Exception exception;
|
||||||
|
private volatile boolean closing;
|
||||||
|
private int linesPerProject = 0;
|
||||||
|
|
||||||
public TerminalUpdater(BlockingQueue<Entry<String, String>> queue, Path logFile) throws IOException {
|
public TerminalUpdater(BlockingQueue<Event> queue, Path logFile) throws IOException {
|
||||||
super();
|
super();
|
||||||
this.terminal = TerminalBuilder.terminal();
|
this.terminal = TerminalBuilder.terminal();
|
||||||
|
terminal.enterRawMode();
|
||||||
this.display = new Display(terminal, false);
|
this.display = new Display(terminal, false);
|
||||||
this.log = logFile == null ? new ClientOutput.Log.MessageCollector(terminal)
|
this.log = logFile == null ? new ClientOutput.Log.MessageCollector(terminal)
|
||||||
: new ClientOutput.Log.FileLog(logFile);
|
: new ClientOutput.Log.FileLog(logFile);
|
||||||
@@ -134,37 +164,88 @@ public interface ClientOutput extends AutoCloseable, Consumer<String> {
|
|||||||
final Thread w = new Thread(this::run);
|
final Thread w = new Thread(this::run);
|
||||||
w.start();
|
w.start();
|
||||||
this.worker = w;
|
this.worker = w;
|
||||||
|
final Thread r = new Thread(this::read);
|
||||||
|
r.start();
|
||||||
|
this.reader = r;
|
||||||
|
}
|
||||||
|
|
||||||
|
void read() {
|
||||||
|
try {
|
||||||
|
while (!closing) {
|
||||||
|
int c = terminal.reader().read(10);
|
||||||
|
if (c == -1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (c == '+' || c == '-' || c == CTRL_L) {
|
||||||
|
queue.add(new Event(EventType.INPUT, null, Character.toString(c)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (InterruptedIOException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
} catch (IOException e) {
|
||||||
|
this.exception = e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void run() {
|
void run() {
|
||||||
final List<Entry<String, String>> entries = new ArrayList<>();
|
final List<Event> entries = new ArrayList<>();
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
try {
|
try {
|
||||||
entries.add(queue.take());
|
entries.add(queue.take());
|
||||||
queue.drainTo(entries);
|
queue.drainTo(entries);
|
||||||
for (Entry<String, String> entry : entries) {
|
for (Event entry : entries) {
|
||||||
final String key = entry.getKey();
|
switch (entry.type) {
|
||||||
final String value = entry.getValue();
|
case END_OF_STREAM: {
|
||||||
if (key == END_OF_STREAM) {
|
projects.values().stream().flatMap(p -> p.log.stream()).forEach(log);
|
||||||
display.update(Collections.emptyList(), 0);
|
display.update(Collections.emptyList(), 0);
|
||||||
LOGGER.debug("Done receiving, printing log");
|
LOGGER.debug("Done receiving, printing log");
|
||||||
log.close();
|
log.close();
|
||||||
LOGGER.debug("Done !");
|
LOGGER.debug("Done !");
|
||||||
terminal.flush();
|
terminal.flush();
|
||||||
return;
|
return;
|
||||||
} else if (key == LOG) {
|
}
|
||||||
log.accept(value);
|
case LOG: {
|
||||||
} else if (key == ERROR) {
|
if (entry.projectId != null) {
|
||||||
|
Project prj = projects.computeIfAbsent(entry.projectId, p -> new Project());
|
||||||
|
prj.log.add(entry.message);
|
||||||
|
} else {
|
||||||
|
log.accept(entry.message);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ERROR: {
|
||||||
|
projects.values().stream().flatMap(p -> p.log.stream()).forEach(log);
|
||||||
display.update(Collections.emptyList(), 0);
|
display.update(Collections.emptyList(), 0);
|
||||||
final AttributedStyle s = new AttributedStyle().bold().foreground(AttributedStyle.RED);
|
final AttributedStyle s = new AttributedStyle().bold().foreground(AttributedStyle.RED);
|
||||||
terminal.writer().println(new AttributedString(value, s).toAnsi());
|
terminal.writer().println(new AttributedString(entry.message, s).toAnsi());
|
||||||
terminal.flush();
|
terminal.flush();
|
||||||
return;
|
return;
|
||||||
} else if (value == null) {
|
}
|
||||||
projects.remove(key);
|
case PROJECT_STATUS:
|
||||||
} else {
|
if (entry.message != null) {
|
||||||
projects.put(key, value);
|
Project prj = projects.computeIfAbsent(entry.projectId, p -> new Project());
|
||||||
|
prj.status = entry.message;
|
||||||
|
} else {
|
||||||
|
Project prj = projects.remove(entry.projectId);
|
||||||
|
if (prj != null) {
|
||||||
|
prj.log.forEach(log);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case INPUT:
|
||||||
|
switch (entry.message.charAt(0)) {
|
||||||
|
case '+':
|
||||||
|
linesPerProject = Math.min(10, linesPerProject + 1);
|
||||||
|
break;
|
||||||
|
case '-':
|
||||||
|
linesPerProject = Math.max(0, linesPerProject - 1);
|
||||||
|
break;
|
||||||
|
case CTRL_L:
|
||||||
|
display.reset();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
entries.clear();
|
entries.clear();
|
||||||
@@ -179,8 +260,12 @@ public interface ClientOutput extends AutoCloseable, Consumer<String> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() throws Exception {
|
public void close() throws Exception {
|
||||||
queue.put(new AbstractMap.SimpleImmutableEntry<>(END_OF_STREAM, null));
|
closing = true;
|
||||||
|
reader.interrupt();
|
||||||
|
queue.put(new Event(EventType.END_OF_STREAM, null, null));
|
||||||
worker.join();
|
worker.join();
|
||||||
|
reader.join();
|
||||||
|
terminal.close();
|
||||||
if (exception != null) {
|
if (exception != null) {
|
||||||
throw exception;
|
throw exception;
|
||||||
}
|
}
|
||||||
@@ -190,35 +275,61 @@ public interface ClientOutput extends AutoCloseable, Consumer<String> {
|
|||||||
// no need to refresh the display at every single step
|
// no need to refresh the display at every single step
|
||||||
final Size size = terminal.getSize();
|
final Size size = terminal.getSize();
|
||||||
final int rows = size.getRows();
|
final int rows = size.getRows();
|
||||||
|
final int cols = size.getColumns();
|
||||||
display.resize(rows, size.getColumns());
|
display.resize(rows, size.getColumns());
|
||||||
if (rows <= 0) {
|
if (rows <= 0) {
|
||||||
display.update(Collections.emptyList(), 0);
|
display.update(Collections.emptyList(), 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final int displayableProjectCount = rows - 1;
|
final List<AttributedString> lines = new ArrayList<>(rows);
|
||||||
final int skipRows = projects.size() > displayableProjectCount ? projects.size() - displayableProjectCount : 0;
|
final int dispLines = rows - 1;
|
||||||
final List<AttributedString> lines = new ArrayList<>(projects.size() - skipRows);
|
if (projects.size() <= dispLines) {
|
||||||
final int lineMaxLength = size.getColumns();
|
lines.add(new AttributedString("Building..."));
|
||||||
int i = 0;
|
int remLogLines = dispLines - projects.size();
|
||||||
lines.add(new AttributedString("Building..." + (skipRows > 0 ? " (" + skipRows + " more)" : "")));
|
for (Project prj : projects.values()) {
|
||||||
for (String line : projects.values()) {
|
lines.add(AttributedString.fromAnsi(prj.status));
|
||||||
if (i < skipRows) {
|
// get the last lines of the project log, taking multi-line logs into account
|
||||||
i++;
|
List<AttributedString> logs = lastN(prj.log, linesPerProject).stream()
|
||||||
} else {
|
.flatMap(s -> AttributedString.fromAnsi(s).columnSplitLength(Integer.MAX_VALUE).stream())
|
||||||
lines.add(shortenIfNeeded(AttributedString.fromAnsi(line), lineMaxLength));
|
.map(s -> concat(" ", s))
|
||||||
|
.collect(lastN(Math.min(remLogLines, linesPerProject)));
|
||||||
|
lines.addAll(logs);
|
||||||
|
remLogLines -= logs.size();
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
lines.add(new AttributedString("Building... (" + (projects.size() - dispLines) + " more)"));
|
||||||
|
lines.addAll(projects.values().stream()
|
||||||
|
.map(prj -> AttributedString.fromAnsi(prj.status))
|
||||||
|
.collect(lastN(dispLines)));
|
||||||
}
|
}
|
||||||
display.update(lines, -1);
|
List<AttributedString> trimmed = lines.stream()
|
||||||
|
.map(s -> s.columnSubSequence(0, cols))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
display.update(trimmed, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static AttributedString shortenIfNeeded(AttributedString s, int length) {
|
private static <T> List<T> lastN(List<T> list, int n) {
|
||||||
if (s == null) {
|
return list.subList(Math.max(0, list.size() - n), list.size());
|
||||||
return null;
|
}
|
||||||
}
|
|
||||||
if (s.length() > length) {
|
private static <T> Collector<T, ?, List<T>> lastN(int n) {
|
||||||
return s.columnSubSequence(0, length - 1);
|
return Collector.<T, Deque<T>, List<T>> of(ArrayDeque::new, (acc, t) -> {
|
||||||
}
|
if (acc.size() == n)
|
||||||
return s;
|
acc.pollFirst();
|
||||||
|
acc.add(t);
|
||||||
|
}, (acc1, acc2) -> {
|
||||||
|
while (acc2.size() < n && !acc1.isEmpty()) {
|
||||||
|
acc2.addFirst(acc1.pollLast());
|
||||||
|
}
|
||||||
|
return acc2;
|
||||||
|
}, ArrayList::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static AttributedString concat(String s1, AttributedString s2) {
|
||||||
|
AttributedStringBuilder asb = new AttributedStringBuilder();
|
||||||
|
asb.append(s1);
|
||||||
|
asb.append(s2);
|
||||||
|
return asb.toAttributedString();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -128,7 +128,7 @@ public class DefaultClient implements Client {
|
|||||||
+ "-" + buildProperties.getOsArch()
|
+ "-" + buildProperties.getOsArch()
|
||||||
+ nativeSuffix)
|
+ nativeSuffix)
|
||||||
.reset().toString();
|
.reset().toString();
|
||||||
output.accept(v);
|
output.accept(null, v);
|
||||||
/*
|
/*
|
||||||
* Do not return, rather pass -v to the server so that the client module does not need to depend on any
|
* Do not return, rather pass -v to the server so that the client module does not need to depend on any
|
||||||
* Maven artifacts
|
* Maven artifacts
|
||||||
@@ -140,9 +140,9 @@ public class DefaultClient implements Client {
|
|||||||
try (DaemonRegistry registry = new DaemonRegistry(layout.registry())) {
|
try (DaemonRegistry registry = new DaemonRegistry(layout.registry())) {
|
||||||
boolean status = args.remove("--status");
|
boolean status = args.remove("--status");
|
||||||
if (status) {
|
if (status) {
|
||||||
output.accept(String.format(" %36s %7s %5s %7s %s",
|
output.accept(null, String.format(" %36s %7s %5s %7s %s",
|
||||||
"UUID", "PID", "Port", "Status", "Last activity"));
|
"UUID", "PID", "Port", "Status", "Last activity"));
|
||||||
registry.getAll().forEach(d -> output.accept(String.format(" %36s %7s %5s %7s %s",
|
registry.getAll().forEach(d -> output.accept(null, String.format(" %36s %7s %5s %7s %s",
|
||||||
d.getUid(), d.getPid(), d.getAddress(), d.getState(),
|
d.getUid(), d.getPid(), d.getAddress(), d.getState(),
|
||||||
LocalDateTime.ofInstant(
|
LocalDateTime.ofInstant(
|
||||||
Instant.ofEpochMilli(Math.max(d.getLastIdle(), d.getLastBusy())),
|
Instant.ofEpochMilli(Math.max(d.getLastIdle(), d.getLastBusy())),
|
||||||
@@ -153,7 +153,7 @@ public class DefaultClient implements Client {
|
|||||||
if (stop) {
|
if (stop) {
|
||||||
DaemonInfo[] dis = registry.getAll().toArray(new DaemonInfo[0]);
|
DaemonInfo[] dis = registry.getAll().toArray(new DaemonInfo[0]);
|
||||||
if (dis.length > 0) {
|
if (dis.length > 0) {
|
||||||
output.accept("Stopping " + dis.length + " running daemons");
|
output.accept(null, "Stopping " + dis.length + " running daemons");
|
||||||
for (DaemonInfo di : dis) {
|
for (DaemonInfo di : dis) {
|
||||||
try {
|
try {
|
||||||
ProcessHandle.of(di.getPid()).ifPresent(ProcessHandle::destroyForcibly);
|
ProcessHandle.of(di.getPid()).ifPresent(ProcessHandle::destroyForcibly);
|
||||||
@@ -204,15 +204,19 @@ public class DefaultClient implements Client {
|
|||||||
return new DefaultResult(argv, null);
|
return new DefaultResult(argv, null);
|
||||||
case ProjectStarted:
|
case ProjectStarted:
|
||||||
case MojoStarted:
|
case MojoStarted:
|
||||||
|
output.projectStateChanged(be.getProjectId(), be.getDisplay());
|
||||||
|
break;
|
||||||
case MojoStopped:
|
case MojoStopped:
|
||||||
output.projectStateChanged(be.getProjectId(), be.getDisplay());
|
output.projectStateChanged(be.getProjectId(), be.getDisplay());
|
||||||
|
output.projectStateChanged(be.getProjectId(), ":" + be.getProjectId());
|
||||||
break;
|
break;
|
||||||
case ProjectStopped:
|
case ProjectStopped:
|
||||||
output.projectFinished(be.getProjectId());
|
output.projectFinished(be.getProjectId());
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} else if (m instanceof BuildMessage) {
|
} else if (m instanceof BuildMessage) {
|
||||||
BuildMessage bm = (BuildMessage) m;
|
BuildMessage bm = (BuildMessage) m;
|
||||||
output.accept(bm.getMessage());
|
output.accept(bm.getProjectId(), bm.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -51,6 +51,11 @@
|
|||||||
<artifactId>junit-jupiter</artifactId>
|
<artifactId>junit-jupiter</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-simple</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
@@ -146,9 +146,11 @@ public abstract class Message {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class BuildMessage extends Message {
|
public static class BuildMessage extends Message {
|
||||||
|
final String projectId;
|
||||||
final String message;
|
final String message;
|
||||||
|
|
||||||
public BuildMessage(String message) {
|
public BuildMessage(String projectId, String message) {
|
||||||
|
this.projectId = projectId;
|
||||||
this.message = message;
|
this.message = message;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,6 +158,10 @@ public abstract class Message {
|
|||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getProjectId() {
|
||||||
|
return projectId;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "BuildMessage{" +
|
return "BuildMessage{" +
|
||||||
@@ -236,11 +242,13 @@ public abstract class Message {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private BuildMessage readBuildMessage(DataInputStream input) throws IOException {
|
private BuildMessage readBuildMessage(DataInputStream input) throws IOException {
|
||||||
|
String projectId = readUTF(input);
|
||||||
String message = readUTF(input);
|
String message = readUTF(input);
|
||||||
return new BuildMessage(message);
|
return new BuildMessage(projectId.isEmpty() ? null : projectId, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeBuildMessage(DataOutputStream output, BuildMessage value) throws IOException {
|
private void writeBuildMessage(DataOutputStream output, BuildMessage value) throws IOException {
|
||||||
|
writeUTF(output, value.projectId != null ? value.projectId : "");
|
||||||
writeUTF(output, value.message);
|
writeUTF(output, value.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -514,7 +514,6 @@ public class Server implements AutoCloseable, Runnable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() throws Exception {
|
public void close() throws Exception {
|
||||||
sendBuildMessages();
|
|
||||||
super.close();
|
super.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -529,43 +528,38 @@ public class Server implements AutoCloseable, Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onStartProject(ProjectBuild project) {
|
protected void onStartProject(String projectId, String display) {
|
||||||
super.onStartProject(project);
|
super.onStartProject(projectId, display);
|
||||||
sendEvent(Type.ProjectStarted, project);
|
sendEvent(Type.ProjectStarted, projectId, display);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onStopProject(ProjectBuild project) {
|
protected void onStopProject(String projectId, String display) {
|
||||||
sendEvent(Type.ProjectStopped, project);
|
sendEvent(Type.ProjectStopped, projectId, display);
|
||||||
super.onStopProject(project);
|
super.onStopProject(projectId, display);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onStartMojo(ProjectBuild project) {
|
protected void onStartMojo(String projectId, String display) {
|
||||||
super.onStartMojo(project);
|
super.onStartMojo(projectId, display);
|
||||||
sendEvent(Type.MojoStarted, project);
|
sendEvent(Type.MojoStarted, projectId, display);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onStopMojo(ProjectBuild project) {
|
protected void onStopMojo(String projectId, String display) {
|
||||||
sendEvent(Type.MojoStopped, project);
|
sendEvent(Type.MojoStopped, projectId, display);
|
||||||
super.onStopMojo(project);
|
super.onStopMojo(projectId, display);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendEvent(Type type, ProjectBuild project) {
|
@Override
|
||||||
String projectId = project.projectId();
|
protected void onProjectLog(String projectId, String message) {
|
||||||
String disp = project.toDisplay().toAnsi(256, false);
|
queue.add(new BuildMessage(projectId, message));
|
||||||
queue.add(new BuildEvent(type, projectId, disp));
|
super.onProjectLog(projectId, message);
|
||||||
sendBuildMessages();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void sendBuildMessages() {
|
private void sendEvent(Type type, String projectId, String display) {
|
||||||
if (events != null) {
|
queue.add(new BuildEvent(type, projectId, display));
|
||||||
events.stream()
|
|
||||||
.map(s -> s.endsWith("\n") ? s.substring(0, s.length() - 1) : s)
|
|
||||||
.map(BuildMessage::new).forEachOrdered(queue::add);
|
|
||||||
events.clear();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -15,14 +15,13 @@
|
|||||||
*/
|
*/
|
||||||
package org.jboss.fuse.mvnd.logging.smart;
|
package org.jboss.fuse.mvnd.logging.smart;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import org.apache.maven.eventspy.AbstractEventSpy;
|
import org.apache.maven.eventspy.AbstractEventSpy;
|
||||||
import org.apache.maven.execution.ExecutionEvent;
|
import org.apache.maven.execution.ExecutionEvent;
|
||||||
import org.apache.maven.plugin.MojoExecution;
|
import org.apache.maven.plugin.MojoExecution;
|
||||||
import org.apache.maven.project.MavenProject;
|
import org.apache.maven.project.MavenProject;
|
||||||
|
import org.jboss.fuse.mvnd.common.Message;
|
||||||
import org.jline.utils.AttributedString;
|
import org.jline.utils.AttributedString;
|
||||||
import org.slf4j.MDC;
|
import org.slf4j.MDC;
|
||||||
|
|
||||||
@@ -44,17 +43,14 @@ public abstract class AbstractLoggingSpy extends AbstractEventSpy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected Map<String, ProjectBuild> projects;
|
protected Map<String, ProjectBuild> projects;
|
||||||
protected List<String> events;
|
protected List<Message.BuildMessage> events;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void init(Context context) throws Exception {
|
public synchronized void init(Context context) throws Exception {
|
||||||
projects = new LinkedHashMap<>();
|
|
||||||
events = new ArrayList<>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void close() throws Exception {
|
public synchronized void close() throws Exception {
|
||||||
events = null;
|
|
||||||
projects = null;
|
projects = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,73 +93,67 @@ public abstract class AbstractLoggingSpy extends AbstractEventSpy {
|
|||||||
protected void notifySessionFinish(ExecutionEvent event) {
|
protected void notifySessionFinish(ExecutionEvent event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected synchronized void notifyProjectBuildStart(ExecutionEvent event) {
|
protected void notifyProjectBuildStart(ExecutionEvent event) {
|
||||||
ProjectBuild pb = new ProjectBuild();
|
onStartProject(getProjectId(event), getProjectDisplay(event));
|
||||||
pb.project = event.getProject();
|
|
||||||
pb.execution = event.getMojoExecution();
|
|
||||||
pb.events = new ArrayList<>();
|
|
||||||
projects.putIfAbsent(event.getProject().getId(), pb);
|
|
||||||
onStartProject(pb);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void onStartProject(ProjectBuild project) {
|
protected void notifyProjectBuildFinish(ExecutionEvent event) throws Exception {
|
||||||
MDC.put(KEY_PROJECT_ID, project.project.getId());
|
onStopProject(getProjectId(event), getProjectDisplay(event));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void notifyMojoExecutionStart(ExecutionEvent event) {
|
||||||
|
onStartMojo(getProjectId(event), getProjectDisplay(event));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void notifyMojoExecutionFinish(ExecutionEvent event) {
|
||||||
|
onStopMojo(getProjectId(event), getProjectDisplay(event));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void onStartProject(String projectId, String display) {
|
||||||
|
MDC.put(KEY_PROJECT_ID, projectId);
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected synchronized void notifyProjectBuildFinish(ExecutionEvent event) throws Exception {
|
protected void onStopProject(String projectId, String display) {
|
||||||
ProjectBuild pb = projects.remove(event.getProject().getId());
|
|
||||||
if (pb != null) {
|
|
||||||
events.addAll(pb.events);
|
|
||||||
onStopProject(pb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void onStopProject(ProjectBuild project) {
|
|
||||||
update();
|
update();
|
||||||
MDC.remove(KEY_PROJECT_ID);
|
MDC.remove(KEY_PROJECT_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected synchronized void notifyMojoExecutionStart(ExecutionEvent event) {
|
protected void onStartMojo(String projectId, String display) {
|
||||||
ProjectBuild pb = projects.get(event.getProject().getId());
|
|
||||||
if (pb != null) {
|
|
||||||
pb.execution = event.getMojoExecution();
|
|
||||||
onStartMojo(pb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void onStartMojo(ProjectBuild project) {
|
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected synchronized void notifyMojoExecutionFinish(ExecutionEvent event) {
|
protected void onStopMojo(String projectId, String display) {
|
||||||
ProjectBuild pb = projects.get(event.getProject().getId());
|
update();
|
||||||
if (pb != null) {
|
|
||||||
pb.execution = null;
|
|
||||||
onStopMojo(pb);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void onStopMojo(ProjectBuild project) {
|
protected void onProjectLog(String projectId, String message) {
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void update() {
|
protected void update() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void append(String projectId, String event) {
|
private String getProjectId(ExecutionEvent event) {
|
||||||
ProjectBuild project = projectId != null ? projects.get(projectId) : null;
|
return event.getProject().getArtifactId();
|
||||||
if (project != null) {
|
}
|
||||||
project.events.add(event);
|
|
||||||
} else {
|
private String getProjectDisplay(ExecutionEvent event) {
|
||||||
events.add(event);
|
String projectId = getProjectId(event);
|
||||||
}
|
String disp = event.getMojoExecution() != null
|
||||||
|
? ":" + projectId + ":" + event.getMojoExecution().toString()
|
||||||
|
: ":" + projectId;
|
||||||
|
return disp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void append(String projectId, String event) {
|
||||||
|
String msg = event.endsWith("\n") ? event.substring(0, event.length() - 1) : event;
|
||||||
|
onProjectLog(projectId, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static class ProjectBuild {
|
protected static class ProjectBuild {
|
||||||
MavenProject project;
|
MavenProject project;
|
||||||
volatile MojoExecution execution;
|
volatile MojoExecution execution;
|
||||||
List<String> events;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
|
@@ -17,7 +17,9 @@ package org.jboss.fuse.mvnd.logging.smart;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import org.jline.terminal.Size;
|
import org.jline.terminal.Size;
|
||||||
import org.jline.terminal.Terminal;
|
import org.jline.terminal.Terminal;
|
||||||
import org.jline.terminal.TerminalBuilder;
|
import org.jline.terminal.TerminalBuilder;
|
||||||
@@ -26,6 +28,7 @@ import org.jline.utils.Display;
|
|||||||
|
|
||||||
public class MavenLoggingSpy extends AbstractLoggingSpy {
|
public class MavenLoggingSpy extends AbstractLoggingSpy {
|
||||||
|
|
||||||
|
private Map<String, String> projects = new LinkedHashMap<>();
|
||||||
private Terminal terminal;
|
private Terminal terminal;
|
||||||
private Display display;
|
private Display display;
|
||||||
|
|
||||||
@@ -45,9 +48,6 @@ public class MavenLoggingSpy extends AbstractLoggingSpy {
|
|||||||
@Override
|
@Override
|
||||||
public void close() throws Exception {
|
public void close() throws Exception {
|
||||||
display.update(Collections.emptyList(), 0);
|
display.update(Collections.emptyList(), 0);
|
||||||
for (String event : events) {
|
|
||||||
terminal.writer().print(event);
|
|
||||||
}
|
|
||||||
terminal.flush();
|
terminal.flush();
|
||||||
terminal.close();
|
terminal.close();
|
||||||
terminal = null;
|
terminal = null;
|
||||||
@@ -55,13 +55,42 @@ public class MavenLoggingSpy extends AbstractLoggingSpy {
|
|||||||
super.close();
|
super.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onStartProject(String projectId, String display) {
|
||||||
|
projects.put(projectId, display);
|
||||||
|
super.onStartProject(projectId, display);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onStopProject(String projectId, String display) {
|
||||||
|
projects.remove(projectId);
|
||||||
|
super.onStopProject(projectId, display);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onStartMojo(String projectId, String display) {
|
||||||
|
projects.put(projectId, display);
|
||||||
|
super.onStartMojo(projectId, display);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onStopMojo(String projectId, String display) {
|
||||||
|
projects.put(projectId, display);
|
||||||
|
super.onStopMojo(projectId, display);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onProjectLog(String projectId, String message) {
|
||||||
|
super.onProjectLog(projectId, message);
|
||||||
|
}
|
||||||
|
|
||||||
protected void update() {
|
protected void update() {
|
||||||
Size size = terminal.getSize();
|
Size size = terminal.getSize();
|
||||||
display.resize(size.getRows(), size.getColumns());
|
display.resize(size.getRows(), size.getColumns());
|
||||||
List<AttributedString> lines = new ArrayList<>();
|
List<AttributedString> lines = new ArrayList<>();
|
||||||
lines.add(new AttributedString("Building..."));
|
lines.add(new AttributedString("Building..."));
|
||||||
for (ProjectBuild build : projects.values()) {
|
for (String build : projects.values()) {
|
||||||
lines.add(build.toDisplay());
|
lines.add(new AttributedString(build));
|
||||||
}
|
}
|
||||||
display.update(lines, -1);
|
display.update(lines, -1);
|
||||||
}
|
}
|
||||||
|
@@ -17,6 +17,7 @@ package org.jboss.fuse.mvnd.assertj;
|
|||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
@@ -43,7 +44,7 @@ public class MatchInOrderAmongOthers<T extends List<? extends String>> extends C
|
|||||||
.filter(pat -> pat.matcher(m).find())
|
.filter(pat -> pat.matcher(m).find())
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.orElse(null))
|
.orElse(null))
|
||||||
.filter(pat -> pat != null) /* remove null patterns */
|
.filter(Objects::nonNull) /* remove null patterns */
|
||||||
.collect(Collectors.toList())
|
.collect(Collectors.toList())
|
||||||
/* if the mapped patterns equal the input patterns then each pattern matched exactly once */
|
/* if the mapped patterns equal the input patterns then each pattern matched exactly once */
|
||||||
.equals(patterns),
|
.equals(patterns),
|
||||||
|
@@ -32,6 +32,8 @@ import org.junit.jupiter.api.Test;
|
|||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
import org.mockito.Mockito;
|
import org.mockito.Mockito;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
|
||||||
@MvndTest(projectDir = "src/test/projects/multi-module")
|
@MvndTest(projectDir = "src/test/projects/multi-module")
|
||||||
public class MultiModuleTest {
|
public class MultiModuleTest {
|
||||||
|
|
||||||
@@ -71,7 +73,7 @@ public class MultiModuleTest {
|
|||||||
client.execute(output, "clean", "install", "-e").assertSuccess();
|
client.execute(output, "clean", "install", "-e").assertSuccess();
|
||||||
|
|
||||||
final ArgumentCaptor<String> logMessage = ArgumentCaptor.forClass(String.class);
|
final ArgumentCaptor<String> logMessage = ArgumentCaptor.forClass(String.class);
|
||||||
Mockito.verify(output, Mockito.atLeast(1)).accept(logMessage.capture());
|
Mockito.verify(output, Mockito.atLeast(1)).accept(any(), logMessage.capture());
|
||||||
Assertions.assertThat(logMessage.getAllValues())
|
Assertions.assertThat(logMessage.getAllValues())
|
||||||
.satisfiesAnyOf( /* Two orderings are possible */
|
.satisfiesAnyOf( /* Two orderings are possible */
|
||||||
messages -> Assertions.assertThat(messages)
|
messages -> Assertions.assertThat(messages)
|
||||||
|
@@ -30,6 +30,8 @@ import org.junit.jupiter.api.Test;
|
|||||||
import org.mockito.InOrder;
|
import org.mockito.InOrder;
|
||||||
import org.mockito.Mockito;
|
import org.mockito.Mockito;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
|
||||||
@MvndNativeTest(projectDir = "src/test/projects/single-module")
|
@MvndNativeTest(projectDir = "src/test/projects/single-module")
|
||||||
public class SingleModuleNativeIT {
|
public class SingleModuleNativeIT {
|
||||||
|
|
||||||
@@ -57,14 +59,14 @@ public class SingleModuleNativeIT {
|
|||||||
final Properties props = MvndTestUtil.properties(layout.multiModuleProjectDirectory().resolve("pom.xml"));
|
final Properties props = MvndTestUtil.properties(layout.multiModuleProjectDirectory().resolve("pom.xml"));
|
||||||
|
|
||||||
final InOrder inOrder = Mockito.inOrder(o);
|
final InOrder inOrder = Mockito.inOrder(o);
|
||||||
inOrder.verify(o).accept(Mockito.contains("Building single-module"));
|
inOrder.verify(o).accept(any(), Mockito.contains("Building single-module"));
|
||||||
inOrder.verify(o).accept(Mockito.contains(MvndTestUtil.plugin(props, "maven-clean-plugin") + ":clean"));
|
inOrder.verify(o).accept(any(), Mockito.contains(MvndTestUtil.plugin(props, "maven-clean-plugin") + ":clean"));
|
||||||
inOrder.verify(o).accept(Mockito.contains(MvndTestUtil.plugin(props, "maven-compiler-plugin") + ":compile"));
|
inOrder.verify(o).accept(any(), Mockito.contains(MvndTestUtil.plugin(props, "maven-compiler-plugin") + ":compile"));
|
||||||
inOrder.verify(o).accept(Mockito.contains(MvndTestUtil.plugin(props, "maven-compiler-plugin") + ":testCompile"));
|
inOrder.verify(o).accept(any(), Mockito.contains(MvndTestUtil.plugin(props, "maven-compiler-plugin") + ":testCompile"));
|
||||||
inOrder.verify(o).accept(Mockito.contains(MvndTestUtil.plugin(props, "maven-surefire-plugin") + ":test"));
|
inOrder.verify(o).accept(any(), Mockito.contains(MvndTestUtil.plugin(props, "maven-surefire-plugin") + ":test"));
|
||||||
inOrder.verify(o).accept(Mockito.contains(MvndTestUtil.plugin(props, "maven-install-plugin") + ":install"));
|
inOrder.verify(o).accept(any(), Mockito.contains(MvndTestUtil.plugin(props, "maven-install-plugin") + ":install"));
|
||||||
inOrder.verify(o)
|
inOrder.verify(o).accept(any(),
|
||||||
.accept(Mockito.contains("SUCCESS build of project org.jboss.fuse.mvnd.test.single-module:single-module"));
|
Mockito.contains("SUCCESS build of project org.jboss.fuse.mvnd.test.single-module:single-module"));
|
||||||
|
|
||||||
assertJVM(o, props);
|
assertJVM(o, props);
|
||||||
|
|
||||||
|
@@ -29,6 +29,8 @@ import org.junit.jupiter.api.Test;
|
|||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
import org.mockito.Mockito;
|
import org.mockito.Mockito;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
|
||||||
@MvndTest(projectDir = "src/test/projects/single-module")
|
@MvndTest(projectDir = "src/test/projects/single-module")
|
||||||
public class StopStatusTest {
|
public class StopStatusTest {
|
||||||
|
|
||||||
@@ -54,7 +56,7 @@ public class StopStatusTest {
|
|||||||
final ClientOutput output = Mockito.mock(ClientOutput.class);
|
final ClientOutput output = Mockito.mock(ClientOutput.class);
|
||||||
client.execute(output, "--status").assertSuccess();
|
client.execute(output, "--status").assertSuccess();
|
||||||
final ArgumentCaptor<String> logMessage = ArgumentCaptor.forClass(String.class);
|
final ArgumentCaptor<String> logMessage = ArgumentCaptor.forClass(String.class);
|
||||||
Mockito.verify(output, Mockito.atLeast(1)).accept(logMessage.capture());
|
Mockito.verify(output, Mockito.atLeast(1)).accept(any(), logMessage.capture());
|
||||||
Assertions.assertThat(logMessage.getAllValues())
|
Assertions.assertThat(logMessage.getAllValues())
|
||||||
.is(new MatchInOrderAmongOthers<>(
|
.is(new MatchInOrderAmongOthers<>(
|
||||||
d.getUid() + " +" + d.getPid() + " +" + d.getAddress()));
|
d.getUid() + " +" + d.getPid() + " +" + d.getAddress()));
|
||||||
@@ -76,7 +78,7 @@ public class StopStatusTest {
|
|||||||
final ClientOutput output = Mockito.mock(ClientOutput.class);
|
final ClientOutput output = Mockito.mock(ClientOutput.class);
|
||||||
client.execute(output, "--status").assertSuccess();
|
client.execute(output, "--status").assertSuccess();
|
||||||
final ArgumentCaptor<String> logMessage = ArgumentCaptor.forClass(String.class);
|
final ArgumentCaptor<String> logMessage = ArgumentCaptor.forClass(String.class);
|
||||||
Mockito.verify(output, Mockito.atLeast(1)).accept(logMessage.capture());
|
Mockito.verify(output, Mockito.atLeast(1)).accept(any(), logMessage.capture());
|
||||||
Assertions.assertThat(
|
Assertions.assertThat(
|
||||||
logMessage.getAllValues().stream()
|
logMessage.getAllValues().stream()
|
||||||
.filter(m -> m.contains(d.getUid()))
|
.filter(m -> m.contains(d.getUid()))
|
||||||
|
@@ -28,6 +28,8 @@ import org.junit.jupiter.api.Test;
|
|||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
import org.mockito.Mockito;
|
import org.mockito.Mockito;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
|
||||||
@MvndNativeTest(projectDir = MvndTestExtension.TEMP_EXTERNAL)
|
@MvndNativeTest(projectDir = MvndTestExtension.TEMP_EXTERNAL)
|
||||||
public class VersionNativeIT {
|
public class VersionNativeIT {
|
||||||
|
|
||||||
@@ -44,7 +46,7 @@ public class VersionNativeIT {
|
|||||||
client.execute(output, "-v").assertSuccess();
|
client.execute(output, "-v").assertSuccess();
|
||||||
|
|
||||||
final ArgumentCaptor<String> logMessage = ArgumentCaptor.forClass(String.class);
|
final ArgumentCaptor<String> logMessage = ArgumentCaptor.forClass(String.class);
|
||||||
Mockito.verify(output, Mockito.atLeast(1)).accept(logMessage.capture());
|
Mockito.verify(output, Mockito.atLeast(1)).accept(any(), logMessage.capture());
|
||||||
|
|
||||||
Assertions.assertThat(logMessage.getAllValues())
|
Assertions.assertThat(logMessage.getAllValues())
|
||||||
.is(new MatchInOrderAmongOthers<>(
|
.is(new MatchInOrderAmongOthers<>(
|
||||||
|
@@ -26,7 +26,6 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import org.jboss.fuse.mvnd.client.Client;
|
import org.jboss.fuse.mvnd.client.Client;
|
||||||
import org.jboss.fuse.mvnd.client.ClientLayout;
|
import org.jboss.fuse.mvnd.client.ClientLayout;
|
||||||
import org.jboss.fuse.mvnd.client.ClientOutput;
|
import org.jboss.fuse.mvnd.client.ClientOutput;
|
||||||
@@ -57,7 +56,7 @@ public class NativeTestClient implements Client {
|
|||||||
public ExecutionResult execute(ClientOutput output, List<String> args) throws InterruptedException {
|
public ExecutionResult execute(ClientOutput output, List<String> args) throws InterruptedException {
|
||||||
final List<String> cmd = new ArrayList<String>(args.size() + 1);
|
final List<String> cmd = new ArrayList<String>(args.size() + 1);
|
||||||
cmd.add(mvndNativeExecutablePath.toString());
|
cmd.add(mvndNativeExecutablePath.toString());
|
||||||
args.stream().forEach(cmd::add);
|
cmd.addAll(args);
|
||||||
if (!Environment.MVND_PROPERTIES_PATH.hasCommandLineProperty(args)) {
|
if (!Environment.MVND_PROPERTIES_PATH.hasCommandLineProperty(args)) {
|
||||||
cmd.add(Environment.MVND_PROPERTIES_PATH.asCommandLineProperty(layout.getMvndPropertiesPath().toString()));
|
cmd.add(Environment.MVND_PROPERTIES_PATH.asCommandLineProperty(layout.getMvndPropertiesPath().toString()));
|
||||||
}
|
}
|
||||||
@@ -81,9 +80,9 @@ public class NativeTestClient implements Client {
|
|||||||
if (!Environment.JAVA_HOME.hasCommandLineProperty(args)) {
|
if (!Environment.JAVA_HOME.hasCommandLineProperty(args)) {
|
||||||
env.put("JAVA_HOME", System.getProperty("java.home"));
|
env.put("JAVA_HOME", System.getProperty("java.home"));
|
||||||
}
|
}
|
||||||
final String cmdString = cmd.stream().collect(Collectors.joining(" "));
|
final String cmdString = String.join(" ", cmd);
|
||||||
output.accept("Executing " + cmdString);
|
output.accept(null, "Executing " + cmdString);
|
||||||
try (CommandProcess process = new CommandProcess(builder.start(), cmd, output)) {
|
try (CommandProcess process = new CommandProcess(builder.start(), cmd, s -> output.accept(null, s))) {
|
||||||
return process.waitFor(timeoutMs);
|
return process.waitFor(timeoutMs);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException("Could not execute: " + cmdString, e);
|
throw new RuntimeException("Could not execute: " + cmdString, e);
|
||||||
@@ -127,7 +126,7 @@ public class NativeTestClient implements Client {
|
|||||||
}
|
}
|
||||||
sb.append("\n--- stderr+stdout start ---");
|
sb.append("\n--- stderr+stdout start ---");
|
||||||
synchronized (log) {
|
synchronized (log) {
|
||||||
log.stream().forEach(s -> sb.append('\n').append(s));
|
log.forEach(s -> sb.append('\n').append(s));
|
||||||
}
|
}
|
||||||
sb.append("\n--- stderr+stdout end ---");
|
sb.append("\n--- stderr+stdout end ---");
|
||||||
throw new AssertionError(sb);
|
throw new AssertionError(sb);
|
||||||
|
Reference in New Issue
Block a user