You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by ap...@apache.org on 2023/10/02 12:57:46 UTC
[ignite-3] branch main updated: IGNITE-20494 Fix sql command that does not enter repl (#2632)
This is an automated email from the ASF dual-hosted git repository.
apkhmv pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git
The following commit(s) were added to refs/heads/main by this push:
new de28ccedc3 IGNITE-20494 Fix sql command that does not enter repl (#2632)
de28ccedc3 is described below
commit de28ccedc3708e405b156bda4fb69d0c6da1d8c5
Author: Vadim Pakhnushev <86...@users.noreply.github.com>
AuthorDate: Mon Oct 2 15:57:40 2023 +0300
IGNITE-20494 Fix sql command that does not enter repl (#2632)
---
.../cli/commands/sql/ItSqlReplCommandTest.java | 47 ++++++
.../java/org/apache/ignite/internal/cli/Main.java | 4 +-
.../internal/cli/commands/sql/SqlReplCommand.java | 3 +-
.../cli/core/repl/executor/ReplExecutor.java | 181 +--------------------
.../{ReplExecutor.java => ReplExecutorImpl.java} | 5 +-
.../core/repl/executor/ReplExecutorProvider.java | 28 +---
...Provider.java => ReplExecutorProviderImpl.java} | 5 +-
7 files changed, 63 insertions(+), 210 deletions(-)
diff --git a/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/sql/ItSqlReplCommandTest.java b/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/sql/ItSqlReplCommandTest.java
index 89291c22dc..5e0c17f2a2 100644
--- a/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/sql/ItSqlReplCommandTest.java
+++ b/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/sql/ItSqlReplCommandTest.java
@@ -19,7 +19,10 @@ package org.apache.ignite.internal.cli.commands.sql;
import static org.junit.jupiter.api.Assertions.assertAll;
+import io.micronaut.context.annotation.Bean;
+import io.micronaut.context.annotation.Replaces;
import org.apache.ignite.internal.cli.commands.CliCommandTestInitializedIntegrationBase;
+import org.apache.ignite.internal.cli.core.repl.executor.ReplExecutorProvider;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
@@ -41,4 +44,48 @@ class ItSqlReplCommandTest extends CliCommandTestInitializedIntegrationBase {
() -> assertErrOutputContains("File with command not found")
);
}
+
+ @Test
+ void secondInvocationScript() {
+ execute("CREATE TABLE T(K INT PRIMARY KEY)", "--jdbc-url", JDBC_URL);
+
+ assertAll(
+ () -> assertOutputContains("Updated 0 rows."),
+ this::assertErrOutputIsEmpty
+ );
+
+ resetOutput();
+
+ execute("--jdbc-url", JDBC_URL);
+
+ assertAll(
+ this::assertOutputIsEmpty,
+ this::assertErrOutputIsEmpty
+ );
+ }
+
+ @Test
+ void secondInvocationFile() {
+ execute("-f", "nonexisting", "--jdbc-url", JDBC_URL);
+
+ assertAll(
+ this::assertOutputIsEmpty,
+ () -> assertErrOutputContains("File with command not found")
+ );
+
+ resetOutput();
+
+ execute("--jdbc-url", JDBC_URL);
+
+ assertAll(
+ this::assertOutputIsEmpty,
+ this::assertErrOutputIsEmpty
+ );
+ }
+
+ @Bean
+ @Replaces(ReplExecutorProvider.class)
+ public ReplExecutorProvider replExecutorProvider() {
+ return () -> repl -> {};
+ }
}
diff --git a/modules/cli/src/main/java/org/apache/ignite/internal/cli/Main.java b/modules/cli/src/main/java/org/apache/ignite/internal/cli/Main.java
index bb05e76083..f198c28060 100644
--- a/modules/cli/src/main/java/org/apache/ignite/internal/cli/Main.java
+++ b/modules/cli/src/main/java/org/apache/ignite/internal/cli/Main.java
@@ -33,7 +33,7 @@ import org.apache.ignite.internal.cli.commands.TopLevelCliCommand;
import org.apache.ignite.internal.cli.config.ConfigDefaultValueProvider;
import org.apache.ignite.internal.cli.config.StateFolderProvider;
import org.apache.ignite.internal.cli.core.exception.handler.PicocliExecutionExceptionHandler;
-import org.apache.ignite.internal.cli.core.repl.executor.ReplExecutorProvider;
+import org.apache.ignite.internal.cli.core.repl.executor.ReplExecutorProviderImpl;
import org.fusesource.jansi.AnsiConsole;
import picocli.CommandLine;
import picocli.CommandLine.Help.Ansi;
@@ -79,7 +79,7 @@ public class Main {
/** Needed for immediate REPL mode and for running a command which will stay in REPL mode so we need to init it once. */
private static void initReplExecutor(MicronautFactory micronautFactory) throws Exception {
- ReplExecutorProvider replExecutorProvider = micronautFactory.create(ReplExecutorProvider.class);
+ ReplExecutorProviderImpl replExecutorProvider = micronautFactory.create(ReplExecutorProviderImpl.class);
replExecutorProvider.injectFactory(micronautFactory);
}
diff --git a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/SqlReplCommand.java b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/SqlReplCommand.java
index a2a886488b..1c805fc74a 100644
--- a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/SqlReplCommand.java
+++ b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/SqlReplCommand.java
@@ -78,7 +78,8 @@ public class SqlReplCommand extends BaseCommand implements Runnable {
@Parameters(index = "0", description = "SQL query to execute", defaultValue = Option.NULL_VALUE)
private String command;
- @Option(names = {SCRIPT_FILE_OPTION, SCRIPT_FILE_OPTION_SHORT}, description = SCRIPT_FILE_OPTION_SHORT)
+ @Option(names = {SCRIPT_FILE_OPTION, SCRIPT_FILE_OPTION_SHORT}, description = SCRIPT_FILE_OPTION_SHORT,
+ defaultValue = Option.NULL_VALUE)
private File file;
}
diff --git a/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/executor/ReplExecutor.java b/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/executor/ReplExecutor.java
index a22184a356..41147be168 100644
--- a/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/executor/ReplExecutor.java
+++ b/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/executor/ReplExecutor.java
@@ -17,187 +17,12 @@
package org.apache.ignite.internal.cli.core.repl.executor;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.function.Supplier;
-import org.apache.ignite.internal.cli.commands.node.NodeNameOrUrl;
-import org.apache.ignite.internal.cli.config.StateFolderProvider;
-import org.apache.ignite.internal.cli.core.converters.NodeNameOrUrlConverter;
-import org.apache.ignite.internal.cli.core.exception.ExceptionHandlers;
-import org.apache.ignite.internal.cli.core.exception.handler.PicocliExecutionExceptionHandler;
-import org.apache.ignite.internal.cli.core.exception.handler.ReplExceptionHandlers;
-import org.apache.ignite.internal.cli.core.flow.question.JlineQuestionWriterReaderFactory;
-import org.apache.ignite.internal.cli.core.flow.question.QuestionAskerFactory;
import org.apache.ignite.internal.cli.core.repl.Repl;
-import org.apache.ignite.internal.cli.core.repl.completer.DynamicCompleterActivationPoint;
-import org.apache.ignite.internal.cli.core.repl.completer.DynamicCompleterRegistry;
-import org.apache.ignite.internal.cli.core.repl.completer.filter.CompleterFilter;
-import org.apache.ignite.internal.cli.core.repl.completer.filter.DeployUnitsOptionsFilter;
-import org.apache.ignite.internal.cli.core.repl.completer.filter.DynamicCompleterFilter;
-import org.apache.ignite.internal.cli.core.repl.completer.filter.NonRepeatableOptionsFilter;
-import org.apache.ignite.internal.cli.core.repl.completer.filter.ShortOptionsFilter;
-import org.apache.ignite.internal.cli.core.repl.context.CommandLineContextProvider;
-import org.apache.ignite.internal.cli.core.repl.expander.NoopExpander;
-import org.apache.ignite.internal.cli.core.repl.registry.NodeNameRegistry;
-import org.jline.console.impl.SystemRegistryImpl;
-import org.jline.reader.Completer;
-import org.jline.reader.LineReader;
-import org.jline.reader.LineReader.SuggestionType;
-import org.jline.reader.LineReaderBuilder;
-import org.jline.reader.MaskingCallback;
-import org.jline.reader.Parser;
-import org.jline.reader.impl.DefaultParser;
-import org.jline.terminal.Terminal;
-import org.jline.widget.AutosuggestionWidgets;
-import org.jline.widget.TailTipWidgets;
-import picocli.CommandLine;
-import picocli.CommandLine.IDefaultValueProvider;
-import picocli.shell.jline3.PicocliCommands.PicocliCommandsFactory;
/**
* Executor of {@link Repl}.
*/
-public class ReplExecutor {
-
- private final Parser parser = new DefaultParser().escapeChars(null);
-
- private final Supplier<Path> workDirProvider = () -> Paths.get(System.getProperty("user.dir"));
-
- private final AtomicBoolean interrupted = new AtomicBoolean();
-
- private final ExceptionHandlers exceptionHandlers = new ReplExceptionHandlers(interrupted::set);
-
- private final PicocliCommandsFactory factory;
-
- private final Terminal terminal;
-
- private final NodeNameRegistry nodeNameRegistry;
-
- /**
- * Constructor.
- *
- * @param commandsFactory picocli commands factory.
- * @param terminal terminal instance.
- * @param nodeNameRegistry node name registry.
- */
- public ReplExecutor(PicocliCommandsFactory commandsFactory, Terminal terminal, NodeNameRegistry nodeNameRegistry) {
- this.factory = commandsFactory;
- this.terminal = terminal;
- this.nodeNameRegistry = nodeNameRegistry;
- }
-
- private static void createTailTipWidgets(SystemRegistryImpl registry, LineReader reader) {
- TailTipWidgets widgets = new TailTipWidgets(reader, registry::commandDescription, 5,
- TailTipWidgets.TipType.COMPLETER);
- widgets.enable();
- // Workaround for the scroll truncation issue in windows terminal
- // Turn off tailtip widgets before printing to the output
- CommandLineContextProvider.setPrintWrapper(printer -> {
- widgets.disable();
- printer.run();
- widgets.enable();
- });
- // Workaround for jline issue where TailTipWidgets will produce NPE when passed a bracket
- registry.setScriptDescription(cmdLine -> null);
- }
-
- /**
- * Executor method. This is thread blocking method, until REPL stop executing.
- *
- * @param repl data class of executing REPL.
- */
- public void execute(Repl repl) {
- try {
- repl.customizeTerminal(terminal);
-
- IgnitePicocliCommands picocliCommands = createPicocliCommands(repl);
- SystemRegistryImpl registry = new SystemRegistryImpl(parser, terminal, workDirProvider, null);
- registry.setCommandRegistries(picocliCommands);
-
- LineReader reader = createReader(
- repl.getCompleter() != null
- ? repl.getCompleter()
- : registry.completer()
- );
- if (repl.getHistoryFileName() != null) {
- reader.variable(LineReader.HISTORY_FILE, StateFolderProvider.getStateFile(repl.getHistoryFileName()));
- }
-
- RegistryCommandExecutor executor = new RegistryCommandExecutor(parser, picocliCommands.getCmd());
-
- setupWidgets(repl, registry, reader);
-
- repl.getEventListeningActivationPoint().subscribe();
-
- repl.onStart();
-
- while (!interrupted.get()) {
- try {
- executor.cleanUp();
- String prompt = repl.getPromptProvider().getPrompt();
- String line = reader.readLine(prompt, null, (MaskingCallback) null, null);
- if (line.isEmpty()) {
- continue;
- }
-
- repl.getPipeline(executor, exceptionHandlers, line).runPipeline();
- } catch (Throwable t) {
- exceptionHandlers.handleException(System.err::println, t);
- }
- }
- reader.getHistory().save();
- } catch (Throwable t) {
- exceptionHandlers.handleException(System.err::println, t);
- }
- }
-
- private void setupWidgets(Repl repl, SystemRegistryImpl registry, LineReader reader) {
- if (repl.isTailTipWidgetsEnabled()) {
- createTailTipWidgets(registry, reader);
- } else if (repl.isAutosuggestionsWidgetsEnabled()) {
- AutosuggestionWidgets widgets = new AutosuggestionWidgets(reader);
- widgets.enable();
- }
-
- QuestionAskerFactory.setWriterReaderFactory(new JlineQuestionWriterReaderFactory(terminal));
- }
-
- private LineReader createReader(Completer completer) {
- LineReader result = LineReaderBuilder.builder()
- .terminal(terminal)
- .completer(completer)
- .parser(parser)
- .expander(new NoopExpander())
- .variable(LineReader.LIST_MAX, 50) // max tab completion candidates
- .build();
- result.setAutosuggestion(SuggestionType.COMPLETER);
- return result;
- }
-
- private IgnitePicocliCommands createPicocliCommands(Repl repl) throws Exception {
- CommandLine cmd = new CommandLine(repl.commandClass(), factory);
- IDefaultValueProvider defaultValueProvider = repl.defaultValueProvider();
- if (defaultValueProvider != null) {
- cmd.setDefaultValueProvider(defaultValueProvider);
- }
- CommandLineContextProvider.setCmd(cmd);
- cmd.setExecutionExceptionHandler(new PicocliExecutionExceptionHandler(exceptionHandlers));
- cmd.registerConverter(NodeNameOrUrl.class, new NodeNameOrUrlConverter(nodeNameRegistry));
- cmd.setTrimQuotes(true);
-
- DynamicCompleterRegistry completerRegistry = factory.create(DynamicCompleterRegistry.class);
- DynamicCompleterActivationPoint activationPoint = factory.create(DynamicCompleterActivationPoint.class);
- activationPoint.activateDynamicCompleter(completerRegistry);
-
- DynamicCompleterFilter dynamicCompleterFilter = factory.create(DynamicCompleterFilter.class);
- List<CompleterFilter> filters = List.of(dynamicCompleterFilter,
- new ShortOptionsFilter(),
- new NonRepeatableOptionsFilter(cmd.getCommandSpec()),
- new DeployUnitsOptionsFilter()
- );
-
- return new IgnitePicocliCommands(cmd, completerRegistry, filters);
- }
+@FunctionalInterface
+public interface ReplExecutor {
+ void execute(Repl repl);
}
diff --git a/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/executor/ReplExecutor.java b/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/executor/ReplExecutorImpl.java
similarity index 97%
copy from modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/executor/ReplExecutor.java
copy to modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/executor/ReplExecutorImpl.java
index a22184a356..cf06e43725 100644
--- a/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/executor/ReplExecutor.java
+++ b/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/executor/ReplExecutorImpl.java
@@ -59,7 +59,7 @@ import picocli.shell.jline3.PicocliCommands.PicocliCommandsFactory;
/**
* Executor of {@link Repl}.
*/
-public class ReplExecutor {
+public class ReplExecutorImpl implements ReplExecutor {
private final Parser parser = new DefaultParser().escapeChars(null);
@@ -82,7 +82,7 @@ public class ReplExecutor {
* @param terminal terminal instance.
* @param nodeNameRegistry node name registry.
*/
- public ReplExecutor(PicocliCommandsFactory commandsFactory, Terminal terminal, NodeNameRegistry nodeNameRegistry) {
+ public ReplExecutorImpl(PicocliCommandsFactory commandsFactory, Terminal terminal, NodeNameRegistry nodeNameRegistry) {
this.factory = commandsFactory;
this.terminal = terminal;
this.nodeNameRegistry = nodeNameRegistry;
@@ -108,6 +108,7 @@ public class ReplExecutor {
*
* @param repl data class of executing REPL.
*/
+ @Override
public void execute(Repl repl) {
try {
repl.customizeTerminal(terminal);
diff --git a/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/executor/ReplExecutorProvider.java b/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/executor/ReplExecutorProvider.java
index 582a175d61..3eef59870f 100644
--- a/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/executor/ReplExecutorProvider.java
+++ b/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/executor/ReplExecutorProvider.java
@@ -17,32 +17,10 @@
package org.apache.ignite.internal.cli.core.repl.executor;
-import io.micronaut.configuration.picocli.MicronautFactory;
-import jakarta.inject.Inject;
-import jakarta.inject.Singleton;
-import org.apache.ignite.internal.cli.core.repl.registry.NodeNameRegistry;
-import org.jline.terminal.Terminal;
-import picocli.shell.jline3.PicocliCommands.PicocliCommandsFactory;
-
/**
* Provider of {@link ReplExecutor}.
*/
-@Singleton
-public class ReplExecutorProvider {
- private PicocliCommandsFactory factory;
-
- @Inject
- private Terminal terminal;
-
- @Inject
- private NodeNameRegistry nodeNameRegistry;
-
- public ReplExecutor get() {
- return new ReplExecutor(factory, terminal, nodeNameRegistry);
- }
-
- public void injectFactory(MicronautFactory micronautFactory) {
- factory = new PicocliCommandsFactory(micronautFactory);
- factory.setTerminal(terminal);
- }
+@FunctionalInterface
+public interface ReplExecutorProvider {
+ ReplExecutor get();
}
diff --git a/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/executor/ReplExecutorProvider.java b/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/executor/ReplExecutorProviderImpl.java
similarity index 90%
copy from modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/executor/ReplExecutorProvider.java
copy to modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/executor/ReplExecutorProviderImpl.java
index 582a175d61..8a66b5a485 100644
--- a/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/executor/ReplExecutorProvider.java
+++ b/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/executor/ReplExecutorProviderImpl.java
@@ -28,7 +28,7 @@ import picocli.shell.jline3.PicocliCommands.PicocliCommandsFactory;
* Provider of {@link ReplExecutor}.
*/
@Singleton
-public class ReplExecutorProvider {
+public class ReplExecutorProviderImpl implements ReplExecutorProvider {
private PicocliCommandsFactory factory;
@Inject
@@ -37,8 +37,9 @@ public class ReplExecutorProvider {
@Inject
private NodeNameRegistry nodeNameRegistry;
+ @Override
public ReplExecutor get() {
- return new ReplExecutor(factory, terminal, nodeNameRegistry);
+ return new ReplExecutorImpl(factory, terminal, nodeNameRegistry);
}
public void injectFactory(MicronautFactory micronautFactory) {