Right-pad projectIds to improve mojo readability in the threaded view #288

This commit is contained in:
Peter Palaga
2020-12-25 21:04:16 +01:00
parent 519424deba
commit c6de4dbd9a
8 changed files with 231 additions and 92 deletions

View File

@@ -32,7 +32,9 @@ public abstract class Message {
public static final int BUILD_REQUEST = 0;
public static final int BUILD_STARTED = 1;
public static final int BUILD_FINISHED = 2;
/** A {@link StringMessage} bearing the {@code artifactId} of the project whose build just started */
public static final int PROJECT_STARTED = 3;
/** A {@link StringMessage} bearing the {@code artifactId} of the project whose build just finished */
public static final int PROJECT_STOPPED = 4;
public static final int MOJO_STARTED = 5;
public static final int PROJECT_LOG_MESSAGE = 6;
@@ -69,9 +71,8 @@ public abstract class Message {
return BuildStarted.read(input);
case BUILD_FINISHED:
return BuildFinished.read(input);
case PROJECT_STARTED:
case PROJECT_STOPPED:
case MOJO_STARTED:
return MojoStartedEvent.read(input);
case PROJECT_LOG_MESSAGE:
case DISPLAY:
return ProjectEvent.read(type, input);
@@ -85,6 +86,8 @@ public abstract class Message {
return Prompt.read(input);
case PROMPT_RESPONSE:
return PromptResponse.read(input);
case PROJECT_STARTED:
case PROJECT_STOPPED:
case BUILD_STATUS:
case BUILD_LOG_MESSAGE:
return StringMessage.read(type, input);
@@ -420,12 +423,6 @@ public abstract class Message {
private String mnemonic() {
switch (type) {
case PROJECT_STARTED:
return "ProjectStarted";
case PROJECT_STOPPED:
return "ProjectStopped";
case MOJO_STARTED:
return "MojoStarted";
case PROJECT_LOG_MESSAGE:
return "ProjectLogMessage";
default:
@@ -441,24 +438,104 @@ public abstract class Message {
}
}
public static class MojoStartedEvent extends Message {
final String artifactId;
final String pluginGroupId;
final String pluginArtifactId;
final String pluginVersion;
final String mojo;
final String executionId;
public static MojoStartedEvent read(DataInputStream input) throws IOException {
final String artifactId = readUTF(input);
final String pluginGroupId = readUTF(input);
final String pluginArtifactId = readUTF(input);
final String pluginVersion = readUTF(input);
final String mojo = readUTF(input);
final String executionId = readUTF(input);
return new MojoStartedEvent(artifactId, pluginGroupId, pluginArtifactId, pluginVersion, mojo, executionId);
}
public MojoStartedEvent(String artifactId, String pluginGroupId, String pluginArtifactId,
String pluginVersion, String mojo, String executionId) {
super(Message.MOJO_STARTED);
this.artifactId = Objects.requireNonNull(artifactId, "artifactId cannot be null");
this.pluginGroupId = Objects.requireNonNull(pluginGroupId, "pluginGroupId cannot be null");
this.pluginArtifactId = Objects.requireNonNull(pluginArtifactId, "pluginArtifactId cannot be null");
this.pluginVersion = Objects.requireNonNull(pluginVersion, "pluginVersion cannot be null");
this.mojo = Objects.requireNonNull(mojo, "mojo cannot be null");
this.executionId = Objects.requireNonNull(executionId, "executionId cannot be null");
}
public String getArtifactId() {
return artifactId;
}
public String getPluginGroupId() {
return pluginGroupId;
}
public String getPluginArtifactId() {
return pluginArtifactId;
}
public String getPluginVersion() {
return pluginVersion;
}
public String getExecutionId() {
return executionId;
}
public String getMojo() {
return mojo;
}
@Override
public String toString() {
return "MojoStarted{" +
"artifactId='" + artifactId + '\'' +
", pluginGroupId='" + pluginGroupId + '\'' +
", pluginArtifactId='" + pluginArtifactId + '\'' +
", pluginVersion='" + pluginVersion + '\'' +
", mojo='" + mojo + '\'' +
", executionId='" + executionId + '\'' +
'}';
}
@Override
public void write(DataOutputStream output) throws IOException {
super.write(output);
writeUTF(output, artifactId);
writeUTF(output, pluginGroupId);
writeUTF(output, pluginArtifactId);
writeUTF(output, pluginVersion);
writeUTF(output, mojo);
writeUTF(output, executionId);
}
}
public static class BuildStarted extends Message {
final String projectId;
final int projectCount;
final int maxThreads;
final int artifactIdDisplayLength;
public static BuildStarted read(DataInputStream input) throws IOException {
final String projectId = readUTF(input);
final int projectCount = input.readInt();
final int maxThreads = input.readInt();
return new BuildStarted(projectId, projectCount, maxThreads);
final int artifactIdDisplayLength = input.readInt();
return new BuildStarted(projectId, projectCount, maxThreads, artifactIdDisplayLength);
}
public BuildStarted(String projectId, int projectCount, int maxThreads) {
public BuildStarted(String projectId, int projectCount, int maxThreads, int artifactIdDisplayLength) {
super(BUILD_STARTED);
this.projectId = projectId;
this.projectCount = projectCount;
this.maxThreads = maxThreads;
this.artifactIdDisplayLength = artifactIdDisplayLength;
}
public String getProjectId() {
@@ -473,11 +550,15 @@ public abstract class Message {
return maxThreads;
}
public int getArtifactIdDisplayLength() {
return artifactIdDisplayLength;
}
@Override
public String toString() {
return "BuildStarted{" +
"projectId='" + projectId + "', projectCount=" + projectCount +
", maxThreads='" + maxThreads + "'}";
", maxThreads=" + maxThreads + ", artifactIdDisplayLength=" + artifactIdDisplayLength + "}";
}
@Override
@@ -486,6 +567,7 @@ public abstract class Message {
writeUTF(output, projectId);
output.writeInt(projectCount);
output.writeInt(maxThreads);
output.writeInt(artifactIdDisplayLength);
}
}
@@ -545,6 +627,10 @@ public abstract class Message {
private String mnemonic() {
switch (type) {
case PROJECT_STARTED:
return "ProjectStarted";
case PROJECT_STOPPED:
return "ProjectStopped";
case BUILD_STATUS:
return "BuildStatus";
case KEYBOARD_INPUT:
@@ -698,16 +784,18 @@ public abstract class Message {
return new StringMessage(KEYBOARD_INPUT, String.valueOf(keyStroke));
}
public static ProjectEvent projectStarted(String projectId, String display) {
return new ProjectEvent(Message.PROJECT_STARTED, projectId, display);
public static StringMessage projectStarted(String projectId) {
return new StringMessage(Message.PROJECT_STARTED, projectId);
}
public static ProjectEvent projectStopped(String projectId, String display) {
return new ProjectEvent(PROJECT_STOPPED, projectId, display);
public static StringMessage projectStopped(String projectId) {
return new StringMessage(PROJECT_STOPPED, projectId);
}
public static Message mojoStarted(String projectId, String display) {
return new ProjectEvent(Message.MOJO_STARTED, projectId, display);
public static Message mojoStarted(String artifactId, String pluginGroupId, String pluginArtifactId,
String pluginVersion, String mojo, String executionId) {
return new MojoStartedEvent(artifactId, pluginGroupId, pluginArtifactId, pluginVersion, mojo, executionId);
}
public static ProjectEvent display(String projectId, String message) {

View File

@@ -44,6 +44,7 @@ import org.jline.utils.Display;
import org.mvndaemon.mvnd.common.Message;
import org.mvndaemon.mvnd.common.Message.BuildException;
import org.mvndaemon.mvnd.common.Message.BuildStarted;
import org.mvndaemon.mvnd.common.Message.MojoStartedEvent;
import org.mvndaemon.mvnd.common.Message.ProjectEvent;
import org.mvndaemon.mvnd.common.Message.StringMessage;
@@ -55,6 +56,8 @@ public class TerminalOutput implements ClientOutput {
public static final int CTRL_B = 'B' & 0x1f;
public static final int CTRL_L = 'L' & 0x1f;
public static final int CTRL_M = 'M' & 0x1f;
private static final AttributedStyle GREEN_FOREGROUND = new AttributedStyle().foreground(AttributedStyle.GREEN);
private static final AttributedStyle CYAN_FOREGROUND = new AttributedStyle().foreground(AttributedStyle.CYAN);
private final Terminal terminal;
private final Terminal.SignalHandler previousIntHandler;
@@ -85,6 +88,7 @@ public class TerminalOutput implements ClientOutput {
/** String format for formatting the number of projects done with padding based on {@link #totalProjects} */
private String projectsDoneFomat;
private int maxThreads;
private String artifactIdFormat;
/** String format for formatting the actual/hidden/max thread counts */
private String threadsFormat;
private int linesPerProject = 0;
@@ -99,7 +103,7 @@ public class TerminalOutput implements ClientOutput {
*/
static class Project {
final String id;
String status;
MojoStartedEvent runningExecution;
final List<String> log = new ArrayList<>();
public Project(String id) {
@@ -171,6 +175,7 @@ public class TerminalOutput implements ClientOutput {
final int totalProjectsDigits = (int) (Math.log10(totalProjects) + 1);
this.projectsDoneFomat = "%" + totalProjectsDigits + "d";
this.maxThreads = bs.getMaxThreads();
this.artifactIdFormat = "%-" + bs.getArtifactIdDisplayLength() + "s ";
final int maxThreadsDigits = (int) (Math.log10(maxThreads) + 1);
this.threadsFormat = "%" + (maxThreadsDigits * 3 + 2) + "s";
if (maxThreads <= 1 || totalProjects <= 1) {
@@ -213,16 +218,22 @@ public class TerminalOutput implements ClientOutput {
terminal.flush();
return false;
}
case Message.PROJECT_STARTED:
case Message.PROJECT_STARTED: {
StringMessage be = (StringMessage) entry;
final String artifactId = be.getMessage();
projects.put(artifactId, new Project(artifactId));
break;
}
case Message.MOJO_STARTED: {
ProjectEvent be = (ProjectEvent) entry;
Project prj = projects.computeIfAbsent(be.getProjectId(), Project::new);
prj.status = be.getMessage();
final MojoStartedEvent execution = (MojoStartedEvent) entry;
final Project prj = projects.get(execution.getArtifactId());
prj.runningExecution = execution;
break;
}
case Message.PROJECT_STOPPED: {
ProjectEvent be = (ProjectEvent) entry;
Project prj = projects.remove(be.getProjectId());
StringMessage be = (StringMessage) entry;
final String artifactId = be.getMessage();
Project prj = projects.remove(artifactId);
if (prj != null) {
prj.log.forEach(log);
}
@@ -444,7 +455,8 @@ public class TerminalOutput implements ClientOutput {
}
final List<AttributedString> lines = new ArrayList<>(rows);
int dispLines = rows - 1; // for the build status line
dispLines--; // there's a bug which sometimes make the cursor goes one line below, so keep one more line empty at the end
dispLines--; // there's a bug which sometimes make the cursor goes one line below, so keep one more line empty
// at the end
final int projectsCount = projects.size();
addStatusLine(lines, dispLines, projectsCount);
@@ -481,7 +493,6 @@ public class TerminalOutput implements ClientOutput {
private void addStatusLine(final List<AttributedString> lines, int dispLines, final int projectsCount) {
if (name != null || buildStatus != null) {
AttributedStringBuilder asb = new AttributedStringBuilder();
StringBuilder statusLine = new StringBuilder(64);
if (name != null) {
asb.append("Building ");
asb.style(AttributedStyle.BOLD);
@@ -489,8 +500,9 @@ public class TerminalOutput implements ClientOutput {
asb.style(AttributedStyle.DEFAULT);
/* Threads */
statusLine
asb
.append(" threads used/hidden/max: ")
.style(AttributedStyle.BOLD)
.append(
String.format(
threadsFormat,
@@ -499,50 +511,63 @@ public class TerminalOutput implements ClientOutput {
.append('/')
.append(Math.max(0, projectsCount - dispLines))
.append('/')
.append(maxThreads).toString()));
.append(maxThreads).toString()))
.style(AttributedStyle.DEFAULT);
/* Progress */
statusLine
asb
.append(" progress: ")
.style(AttributedStyle.BOLD)
.append(String.format(projectsDoneFomat, doneProjects))
.append('/')
.append(totalProjects)
.append(String.valueOf(totalProjects))
.append(' ')
.append(String.format("%3d", doneProjects * 100 / totalProjects))
.append('%');
.append('%')
.style(AttributedStyle.DEFAULT);
} else if (buildStatus != null) {
statusLine.append(buildStatus);
asb
.style(AttributedStyle.BOLD)
.append(buildStatus)
.style(AttributedStyle.DEFAULT);
}
/* Time */
statusLine.append(" time: ");
long sec = (System.currentTimeMillis() - this.start) / 1000;
statusLine.append(String.format("%02d:%02d", sec / 60, sec % 60));
asb
.append(" time: ")
.style(AttributedStyle.BOLD)
.append(String.format("%02d:%02d", sec / 60, sec % 60))
.style(AttributedStyle.DEFAULT);
asb.append(statusLine.toString());
lines.add(asb.toAttributedString());
}
}
private void addProjectLine(final List<AttributedString> lines, Project prj) {
String str = prj.status != null ? prj.status : ":" + prj.id + ":<unknown>";
if (str.length() >= 1 && str.charAt(0) == ':') {
int ce = str.indexOf(':', 1);
final AttributedStringBuilder asb = new AttributedStringBuilder();
asb.append(":");
asb.style(AttributedStyle.BOLD);
if (ce > 0) {
asb.append(str, 1, ce);
asb.style(AttributedStyle.DEFAULT);
asb.append(str, ce, str.length());
} else {
asb.append(str, 1, str.length());
}
lines.add(asb.toAttributedString());
final MojoStartedEvent execution = prj.runningExecution;
final AttributedStringBuilder asb = new AttributedStringBuilder();
if (execution == null) {
asb
.append(':')
.append(prj.id);
} else {
lines.add(AttributedString.fromAnsi(str));
asb
.append(':')
.append(String.format(artifactIdFormat, prj.id))
.style(GREEN_FOREGROUND);
asb
.append(execution.getPluginArtifactId())
.append(':')
.append(execution.getMojo())
.style(AttributedStyle.DEFAULT)
.append(" @ ")
.style(CYAN_FOREGROUND)
.append(execution.getExecutionId())
.style(AttributedStyle.DEFAULT);
}
lines.add(asb.toAttributedString());
}
private static <T> List<T> lastN(List<T> list, int n) {