Make prompting work in the daemon (#1303)
Some checks failed
Early Access / Default build (without GraalVM) (push) Has been cancelled
Early Access / Build with GraalVM on macos-13 (push) Has been cancelled
Early Access / Build with GraalVM on macos-latest (push) Has been cancelled
Early Access / Build with GraalVM on ubuntu-latest (push) Has been cancelled
Early Access / Build with GraalVM on windows-latest (push) Has been cancelled
Early Access / Site build (push) Has been cancelled
Stale / stale (push) Has been cancelled

The daemon was implementing the legacy plexus.interactivity Prompter interface, which Maven 4 no longer
calls. Instead, it needs to implement the new maven.api Prompter interface. This also simplifies the code,
since the legacy prompter handling is now done by Maven core and it delegates to the new interface if an
old plugin uses it.

Also, prompting was skipped on dumb terminals for some reason. This meant that prompting could not be
tested with automated tests using ProcessBuilder. It also meant that piping input into mvnd on the terminal
wouldn't work. This made it inconsistent with regular Maven, which supports promting on a dumb terminal.
I've reactivated it, which makes the prompting integration tests for our Maven extension pass again.

There was also a missing console flush before sending the response to the daemon, which could lead to
inconsistent output, where the newline was sometimes printed before and sometimes after the next line from
the daemon.

Fixes #1292
This commit is contained in:
Stefan Oehme
2025-09-12 13:04:52 +02:00
committed by GitHub
parent 967f6473cf
commit b6bddf2ceb
3 changed files with 11 additions and 37 deletions

View File

@@ -178,6 +178,7 @@ public class TerminalInputHandler implements AutoCloseable {
break; break;
} else if (c == '\n' || c == '\r') { } else if (c == '\n' || c == '\r') {
terminal.writer().println(); terminal.writer().println();
terminal.writer().flush();
daemonDispatch.accept(prompt.response(sb.toString())); daemonDispatch.accept(prompt.response(sb.toString()));
break; break;
} else if (c == 127) { // Backspace } else if (c == 127) { // Backspace

View File

@@ -328,10 +328,6 @@ public class TerminalOutput implements ClientOutput {
} }
case Message.PROMPT: { case Message.PROMPT: {
Message.Prompt prompt = (Message.Prompt) entry; Message.Prompt prompt = (Message.Prompt) entry;
if (dumb) {
terminal.writer().println("");
break;
}
clearDisplay(); clearDisplay();
inputHandler.requestPrompt(prompt); inputHandler.requestPrompt(prompt);
break; break;

View File

@@ -26,12 +26,9 @@ import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.UUID; import java.util.UUID;
import org.apache.maven.api.services.Prompter;
import org.apache.maven.api.services.PrompterException;
import org.apache.maven.logging.ProjectBuildLogAppender; import org.apache.maven.logging.ProjectBuildLogAppender;
import org.codehaus.plexus.components.interactivity.AbstractInputHandler;
import org.codehaus.plexus.components.interactivity.InputHandler;
import org.codehaus.plexus.components.interactivity.OutputHandler;
import org.codehaus.plexus.components.interactivity.Prompter;
import org.codehaus.plexus.components.interactivity.PrompterException;
import org.eclipse.sisu.Priority; import org.eclipse.sisu.Priority;
import org.eclipse.sisu.Typed; import org.eclipse.sisu.Typed;
import org.mvndaemon.mvnd.common.Message; import org.mvndaemon.mvnd.common.Message;
@@ -41,39 +38,39 @@ import org.slf4j.LoggerFactory;
@Named @Named
@Priority(20) @Priority(20)
@Typed({Prompter.class, InputHandler.class, OutputHandler.class}) @Typed({Prompter.class})
public class DaemonPrompter extends AbstractInputHandler implements Prompter, InputHandler, OutputHandler { public class DaemonPrompter implements Prompter {
private static final Logger LOGGER = LoggerFactory.getLogger(DaemonPrompter.class); private static final Logger LOGGER = LoggerFactory.getLogger(DaemonPrompter.class);
@Override @Override
public String prompt(String message) throws PrompterException { public String prompt(String message) {
return prompt(message, null, null); return prompt(message, null, null);
} }
@Override @Override
public String prompt(String message, String defaultReply) throws PrompterException { public String prompt(String message, String defaultReply) {
return prompt(message, null, defaultReply); return prompt(message, null, defaultReply);
} }
@Override @Override
public String prompt(String message, List possibleValues) throws PrompterException { public String prompt(String message, List possibleValues) {
return prompt(message, possibleValues, null); return prompt(message, possibleValues, null);
} }
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public String prompt(String message, List possibleValues, String defaultReply) throws PrompterException { public String prompt(String message, List possibleValues, String defaultReply) {
return doPrompt(message, possibleValues, defaultReply, false); return doPrompt(message, possibleValues, defaultReply, false);
} }
@Override @Override
public String promptForPassword(String message) throws PrompterException { public String promptForPassword(String message) {
return doPrompt(message, null, null, true); return doPrompt(message, null, null, true);
} }
@Override @Override
public void showMessage(String message) throws PrompterException { public void showMessage(String message) {
try { try {
doDisplay(message); doDisplay(message);
} catch (IOException e) { } catch (IOException e) {
@@ -81,26 +78,6 @@ public class DaemonPrompter extends AbstractInputHandler implements Prompter, In
} }
} }
@Override
public String readLine() throws IOException {
return doPrompt(null, false);
}
@Override
public String readPassword() throws IOException {
return doPrompt(null, true);
}
@Override
public void write(String line) throws IOException {
doDisplay(line);
}
@Override
public void writeLine(String line) throws IOException {
doDisplay(line + "\n");
}
String doPrompt(String message, List<Object> possibleValues, String defaultReply, boolean password) String doPrompt(String message, List<Object> possibleValues, String defaultReply, boolean password)
throws PrompterException { throws PrompterException {
String formattedMessage = formatMessage(message, possibleValues, defaultReply); String formattedMessage = formatMessage(message, possibleValues, defaultReply);