diff --git a/pulsar-client-tools/src/main/java/org/apache/pulsar/shell/PulsarShell.java b/pulsar-client-tools/src/main/java/org/apache/pulsar/shell/PulsarShell.java index 3cc99126fb8d7..5007b9df5d1cf 100644 --- a/pulsar-client-tools/src/main/java/org/apache/pulsar/shell/PulsarShell.java +++ b/pulsar-client-tools/src/main/java/org/apache/pulsar/shell/PulsarShell.java @@ -31,6 +31,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Properties; import java.util.Scanner; @@ -130,6 +131,31 @@ enum ExecState { IDLE, RUNNING } + + enum ShellMode { + ADMIN("admin"), + CLIENT("client"), + DEFAULT(""); + + private static final Map COMMAND_MAP = new HashMap<>(); + + static { + for (ShellMode shellMode : values()) { + COMMAND_MAP.put(shellMode.command, shellMode); + } + } + + final String command; + + ShellMode(String command) { + this.command = command; + } + + public static ShellMode valueOfCommand(String command) { + return COMMAND_MAP.get(command); + } + } + private Properties properties; @Getter private final ConfigStore configStore; @@ -142,6 +168,9 @@ enum ExecState { private InteractiveLineReader reader; private final ConfigShell configShell; private ExecState execState = ExecState.IDLE; + private ShellMode shellMode = ShellMode.DEFAULT; + private String prompt; + private String promptMessage; public PulsarShell(String args[]) throws IOException { this(args, new Properties()); @@ -262,26 +291,28 @@ public void run() throws Exception { configureHistory(properties, readerBuilder); LineReader reader = readerBuilder.build(); - final String welcomeMessage = - String.format("Welcome to Pulsar shell!\n %s: %s\n %s: %s\n\n" - + "Type %s to get started or try the autocompletion (TAB button).\n" - + "Type %s or %s to end the shell session.\n", - new AttributedStringBuilder().style(AttributedStyle.BOLD).append("Service URL").toAnsi(), - serviceUrl, - new AttributedStringBuilder().style(AttributedStyle.BOLD).append("Admin URL").toAnsi(), - adminUrl, - new AttributedStringBuilder().style(AttributedStyle.BOLD).append("help").toAnsi(), - new AttributedStringBuilder().style(AttributedStyle.BOLD).append("exit").toAnsi(), - new AttributedStringBuilder().style(AttributedStyle.BOLD).append("quit").toAnsi()); - output(welcomeMessage, terminal); - String promptMessage; - if (configShell.getCurrentConfig() != null) { - promptMessage = String.format("%s(%s)", - configShell.getCurrentConfig(), getHostFromUrl(serviceUrl)); - } else { - promptMessage = getHostFromUrl(serviceUrl); + if (prompt == null) { + final String welcomeMessage = + String.format("Welcome to Pulsar shell!\n %s: %s\n %s: %s\n\n" + + "Type %s to get started or try the autocompletion (TAB button).\n" + + "Type %s or %s to end the shell session.\n", + new AttributedStringBuilder().style(AttributedStyle.BOLD).append("Service URL") + .toAnsi(), serviceUrl, + new AttributedStringBuilder().style(AttributedStyle.BOLD).append("Admin URL").toAnsi(), + adminUrl, + new AttributedStringBuilder().style(AttributedStyle.BOLD).append("help").toAnsi(), + new AttributedStringBuilder().style(AttributedStyle.BOLD).append("exit").toAnsi(), + new AttributedStringBuilder().style(AttributedStyle.BOLD).append("quit").toAnsi()); + output(welcomeMessage, terminal); + + if (configShell.getCurrentConfig() != null) { + promptMessage = String.format("%s(%s)", + configShell.getCurrentConfig(), getHostFromUrl(serviceUrl)); + } else { + promptMessage = getHostFromUrl(serviceUrl); + } + prompt = createPrompt(promptMessage); } - final String prompt = createPrompt(promptMessage); return new InteractiveLineReader() { @Override public String readLine() { @@ -414,23 +445,42 @@ public List readCommand() { return; } execState = ExecState.RUNNING; - final String line = words.stream().collect(Collectors.joining(" ")); + String line = words.stream().collect(Collectors.joining(" ")); if (StringUtils.isBlank(line)) { continue; } if (isQuitCommand(line)) { + if (shellMode != ShellMode.DEFAULT) { + output(String.format("Exiting from %s shell mode", shellMode.command), terminal); + prompt = createPrompt(promptMessage); + shellMode = ShellMode.DEFAULT; + reader = readerBuilder.apply(registerProviders(properties)); + continue; + } exit(0); return; } + if (shellMode == ShellMode.DEFAULT) { + ShellMode newShellMode = ShellMode.valueOfCommand(line.toLowerCase(Locale.ROOT)); + if (newShellMode != null) { + shellMode = newShellMode; + prompt = createPrompt(promptMessage + " " + shellMode.command); + updateShellCommander(properties); + reader = readerBuilder.apply(providersMap); + continue; + } + } if (isHelp(line)) { shellCommander.usage(System.out); continue; } - final ShellCommandsProvider pulsarShellCommandsProvider = getProviderFromArgs(shellCommander, words); - if (pulsarShellCommandsProvider == null) { - shellCommander.usage(System.out); - continue; + if (shellMode == ShellMode.DEFAULT) { + final ShellCommandsProvider pulsarShellCommandsProvider = getProviderFromArgs(shellCommander, words); + if (pulsarShellCommandsProvider == null) { + shellCommander.usage(System.out); + continue; + } } boolean commandOk = false; try { @@ -561,13 +611,37 @@ private Map registerProviders(Properties properti registerProvider(createClientShell(properties), shellCommander, providerMap); registerProvider(configShell, shellCommander, providerMap); + updateSystemRegistry(); + + return providerMap; + } + + private void updateShellCommander(Properties properties) throws Exception { + ShellCommandsProvider shellCommandsProvider = createShellFromMode(properties, shellMode); + shellCommander = shellCommandsProvider.getCommander(); + updateSystemRegistry(); + } + + private void updateSystemRegistry() { Supplier workDir = () -> Paths.get(DEFAULT_PULSAR_SHELL_ROOT_DIRECTORY); PicocliCommands picocliCommands = new PicocliCommands(shellCommander); systemRegistry = new SystemRegistryImpl(parser, terminal, workDir, null); systemRegistry.setCommandRegistries(picocliCommands); systemRegistry.register("help", picocliCommands); + } - return providerMap; + protected ShellCommandsProvider createShellFromMode(Properties properties, ShellMode shellMode) throws Exception { + switch (shellMode) { + case ADMIN -> { + return createAdminShell(properties); + } + case CLIENT -> { + return createClientShell(properties); + } + default -> { + return shellCommander.getCommand(); + } + } } protected AdminShell createAdminShell(Properties properties) throws Exception {