This is an automated email from the ASF dual-hosted git repository.

sk0x50 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 e06ef7eaca IGNITE-18012 Added connect command to start CLI in REPL 
mode. Fixes #1283
e06ef7eaca is described below

commit e06ef7eaca1453a8e189efdd1c5c20bf25d6ff51
Author: Vadim Pakhnushev <[email protected]>
AuthorDate: Wed Nov 16 22:00:24 2022 +0200

    IGNITE-18012 Added connect command to start CLI in REPL mode. Fixes #1283
    
    Signed-off-by: Slava Koptilin <[email protected]>
---
 .../java/org/apache/ignite/internal/cli/Main.java  | 51 ++++------------
 .../apache/ignite/internal/cli/ReplManager.java    | 70 ++++++++++++++++++++++
 .../internal/cli/commands/TopLevelCliCommand.java  |  2 +
 .../cli/commands/TopLevelCliReplCommand.java       |  4 +-
 .../cli/commands/connect/ConnectCommand.java       |  9 ++-
 ...ConnectCommand.java => ConnectReplCommand.java} |  4 +-
 .../questions/ConnectToClusterQuestion.java        |  3 +
 .../cli/commands/UrlOptionsNegativeTest.java       |  6 +-
 8 files changed, 101 insertions(+), 48 deletions(-)

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 0e0d42b7c0..60e361da8e 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
@@ -27,22 +27,13 @@ import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.Arrays;
-import java.util.HashMap;
 import java.util.logging.LogManager;
 import java.util.stream.Collectors;
 import org.apache.ignite.internal.cli.commands.TopLevelCliCommand;
-import org.apache.ignite.internal.cli.commands.TopLevelCliReplCommand;
-import 
org.apache.ignite.internal.cli.commands.questions.ConnectToClusterQuestion;
 import org.apache.ignite.internal.cli.config.ConfigDefaultValueProvider;
 import org.apache.ignite.internal.cli.config.StateFolderProvider;
-import org.apache.ignite.internal.cli.core.call.CallExecutionPipeline;
-import org.apache.ignite.internal.cli.core.call.StringCallInput;
-import 
org.apache.ignite.internal.cli.core.exception.handler.DefaultExceptionHandlers;
 import 
org.apache.ignite.internal.cli.core.exception.handler.PicocliExecutionExceptionHandler;
-import org.apache.ignite.internal.cli.core.repl.Repl;
-import org.apache.ignite.internal.cli.core.repl.SessionDefaultValueProvider;
 import org.apache.ignite.internal.cli.core.repl.executor.ReplExecutorProvider;
-import org.apache.ignite.internal.cli.core.repl.prompt.PromptProvider;
 import org.fusesource.jansi.AnsiConsole;
 import picocli.CommandLine;
 import picocli.CommandLine.Help.Ansi;
@@ -64,6 +55,7 @@ public class Main {
         ApplicationContextBuilder builder = 
ApplicationContext.builder(Environment.CLI).deduceEnvironment(false);
         try (MicronautFactory micronautFactory = new 
MicronautFactory(builder.start())) {
             AnsiConsole.systemInstall();
+            initReplExecutor(micronautFactory);
             if (args.length != 0 || !isatty()) { // do not enter REPL if input 
or output is redirected
                 try {
                     exitCode = executeCommand(args, micronautFactory);
@@ -71,12 +63,10 @@ public class Main {
                     System.err.println("Error occurred during command 
execution");
                 }
             } else {
-                try {
-                    enterRepl(micronautFactory);
-                } catch (Exception e) {
-                    System.err.println("Error occurred during REPL 
initialization");
-                }
+                enterRepl(micronautFactory);
             }
+        } catch (Exception e) {
+            System.err.println("Error occurred during initialization");
         } finally {
             AnsiConsole.systemUninstall();
         }
@@ -87,37 +77,18 @@ public class Main {
         return System.console() != null;
     }
 
-    private static void enterRepl(MicronautFactory micronautFactory) throws 
Exception {
+    /** 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);
         replExecutorProvider.injectFactory(micronautFactory);
-        HashMap<String, String> aliases = new HashMap<>();
-        aliases.put("zle", "widget");
-        aliases.put("bindkey", "keymap");
-
-        SessionDefaultValueProvider defaultValueProvider = 
micronautFactory.create(SessionDefaultValueProvider.class);
+    }
 
+    private static void enterRepl(MicronautFactory micronautFactory) throws 
Exception {
         VersionProvider versionProvider = 
micronautFactory.create(VersionProvider.class);
         System.out.println(banner(versionProvider));
 
-        ConnectToClusterQuestion question = 
micronautFactory.create(ConnectToClusterQuestion.class);
-
-        replExecutorProvider.get().execute(Repl.builder()
-                
.withPromptProvider(micronautFactory.create(PromptProvider.class))
-                .withAliases(aliases)
-                .withCommandClass(TopLevelCliReplCommand.class)
-                .withDefaultValueProvider(defaultValueProvider)
-                .withCallExecutionPipelineProvider((executor, 
exceptionHandlers, line) ->
-                        CallExecutionPipeline.builder(executor)
-                                .inputProvider(() -> new StringCallInput(line))
-                                .output(System.out)
-                                .errOutput(System.err)
-                                .exceptionHandlers(new 
DefaultExceptionHandlers())
-                                .exceptionHandlers(exceptionHandlers)
-                                .build())
-                .withOnStart(question::askQuestionOnReplStart)
-                .withHistoryFileName("history")
-                .withTailTipWidgets()
-                .build());
+        ReplManager replManager = micronautFactory.create(ReplManager.class);
+        replManager.startReplMode();
     }
 
     private static int executeCommand(String[] args, MicronautFactory 
micronautFactory) throws Exception {
@@ -127,7 +98,7 @@ public class Main {
         return cmd.execute(args);
     }
 
-    private static final String[] BANNER = new String[]{
+    private static final String[] BANNER = {
             "",
             "  @|red,bold          #|@              ___                        
 __",
             "  @|red,bold        ###|@             /   |   ____   ____ _ _____ 
/ /_   ___",
diff --git 
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/ReplManager.java 
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/ReplManager.java
new file mode 100644
index 0000000000..c7adf3984f
--- /dev/null
+++ b/modules/cli/src/main/java/org/apache/ignite/internal/cli/ReplManager.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.cli;
+
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+import org.apache.ignite.internal.cli.commands.TopLevelCliReplCommand;
+import 
org.apache.ignite.internal.cli.commands.questions.ConnectToClusterQuestion;
+import org.apache.ignite.internal.cli.core.call.CallExecutionPipeline;
+import org.apache.ignite.internal.cli.core.call.StringCallInput;
+import 
org.apache.ignite.internal.cli.core.exception.handler.DefaultExceptionHandlers;
+import org.apache.ignite.internal.cli.core.repl.Repl;
+import org.apache.ignite.internal.cli.core.repl.SessionDefaultValueProvider;
+import org.apache.ignite.internal.cli.core.repl.executor.ReplExecutorProvider;
+import org.apache.ignite.internal.cli.core.repl.prompt.PromptProvider;
+
+/**
+ * Class which runs main REPL mode, it's used both when starting directly into 
the REPL mode and from the `connect` command.
+ */
+@Singleton
+public class ReplManager {
+    @Inject
+    private ReplExecutorProvider replExecutorProvider;
+
+    @Inject
+    private PromptProvider promptProvider;
+
+    @Inject
+    private SessionDefaultValueProvider defaultValueProvider;
+
+    @Inject
+    private ConnectToClusterQuestion question;
+
+    /**
+     * Enters REPL mode.
+     */
+    public void startReplMode() {
+        replExecutorProvider.get().execute(Repl.builder()
+                .withPromptProvider(promptProvider)
+                .withCommandClass(TopLevelCliReplCommand.class)
+                .withDefaultValueProvider(defaultValueProvider)
+                .withCallExecutionPipelineProvider((executor, 
exceptionHandlers, line) ->
+                        CallExecutionPipeline.builder(executor)
+                                .inputProvider(() -> new StringCallInput(line))
+                                .output(System.out)
+                                .errOutput(System.err)
+                                .exceptionHandlers(new 
DefaultExceptionHandlers())
+                                .exceptionHandlers(exceptionHandlers)
+                                .build())
+                .withOnStart(question::askQuestionOnReplStart)
+                .withHistoryFileName("history")
+                .withTailTipWidgets()
+                .build());
+    }
+}
diff --git 
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/TopLevelCliCommand.java
 
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/TopLevelCliCommand.java
index 3c9c0ed9da..444722a1c5 100644
--- 
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/TopLevelCliCommand.java
+++ 
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/TopLevelCliCommand.java
@@ -20,6 +20,7 @@ package org.apache.ignite.internal.cli.commands;
 import org.apache.ignite.internal.cli.VersionProvider;
 import org.apache.ignite.internal.cli.commands.cliconfig.CliCommand;
 import org.apache.ignite.internal.cli.commands.cluster.ClusterCommand;
+import org.apache.ignite.internal.cli.commands.connect.ConnectCommand;
 import org.apache.ignite.internal.cli.commands.node.NodeCommand;
 import org.apache.ignite.internal.cli.commands.sql.SqlCommand;
 import picocli.CommandLine;
@@ -39,6 +40,7 @@ import picocli.CommandLine.Option;
                 SqlCommand.class,
                 CommandLine.HelpCommand.class,
                 CliCommand.class,
+                ConnectCommand.class,
                 NodeCommand.class,
                 ClusterCommand.class
         })
diff --git 
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/TopLevelCliReplCommand.java
 
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/TopLevelCliReplCommand.java
index 58b4b24ca3..0f801a1c49 100644
--- 
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/TopLevelCliReplCommand.java
+++ 
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/TopLevelCliReplCommand.java
@@ -19,7 +19,7 @@ package org.apache.ignite.internal.cli.commands;
 
 import org.apache.ignite.internal.cli.commands.cliconfig.CliReplCommand;
 import org.apache.ignite.internal.cli.commands.cluster.ClusterReplCommand;
-import org.apache.ignite.internal.cli.commands.connect.ConnectCommand;
+import org.apache.ignite.internal.cli.commands.connect.ConnectReplCommand;
 import org.apache.ignite.internal.cli.commands.connect.DisconnectCommand;
 import org.apache.ignite.internal.cli.commands.node.NodeReplCommand;
 import org.apache.ignite.internal.cli.commands.sql.SqlReplCommand;
@@ -38,7 +38,7 @@ import picocli.shell.jline3.PicocliCommands;
                 CommandLine.HelpCommand.class,
                 VersionCommand.class,
                 CliReplCommand.class,
-                ConnectCommand.class,
+                ConnectReplCommand.class,
                 DisconnectCommand.class,
                 NodeReplCommand.class,
                 ClusterReplCommand.class
diff --git 
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/connect/ConnectCommand.java
 
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/connect/ConnectCommand.java
index 4cac80d24c..9457086550 100644
--- 
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/connect/ConnectCommand.java
+++ 
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/connect/ConnectCommand.java
@@ -21,6 +21,7 @@ import static 
org.apache.ignite.internal.cli.commands.OptionsConstants.CLUSTER_U
 import static 
org.apache.ignite.internal.cli.commands.OptionsConstants.NODE_URL_OR_NAME_DESC;
 
 import jakarta.inject.Inject;
+import org.apache.ignite.internal.cli.ReplManager;
 import org.apache.ignite.internal.cli.call.connect.ConnectCall;
 import org.apache.ignite.internal.cli.call.connect.ConnectCallInput;
 import org.apache.ignite.internal.cli.commands.BaseCommand;
@@ -42,15 +43,21 @@ public class ConnectCommand extends BaseCommand implements 
Runnable {
     @Inject
     private ConnectCall connectCall;
 
+    @Inject
+    private ReplManager replManager;
+
     /** {@inheritDoc} */
     @Override
     public void run() {
-        CallExecutionPipeline.builder(connectCall)
+        int exitCode = CallExecutionPipeline.builder(connectCall)
                 .inputProvider(() -> new 
ConnectCallInput(nodeNameOrUrl.stringUrl()))
                 .output(spec.commandLine().getOut())
                 .errOutput(spec.commandLine().getErr())
                 .verbose(verbose)
                 .build()
                 .runPipeline();
+        if (exitCode == 0) {
+            replManager.startReplMode();
+        }
     }
 }
diff --git 
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/connect/ConnectCommand.java
 
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/connect/ConnectReplCommand.java
similarity index 94%
copy from 
modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/connect/ConnectCommand.java
copy to 
modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/connect/ConnectReplCommand.java
index 4cac80d24c..6f73ea78b5 100644
--- 
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/connect/ConnectCommand.java
+++ 
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/connect/ConnectReplCommand.java
@@ -30,10 +30,10 @@ import picocli.CommandLine.Command;
 import picocli.CommandLine.Parameters;
 
 /**
- * Connects to the Ignite 3 node.
+ * Connects to the Ignite 3 node in REPL mode.
  */
 @Command(name = "connect", description = "Connects to Ignite 3 node")
-public class ConnectCommand extends BaseCommand implements Runnable {
+public class ConnectReplCommand extends BaseCommand implements Runnable {
 
     /** Node URL option. */
     @Parameters(description = NODE_URL_OR_NAME_DESC, descriptionKey = 
CLUSTER_URL_KEY)
diff --git 
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/questions/ConnectToClusterQuestion.java
 
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/questions/ConnectToClusterQuestion.java
index d02a303bfb..b5743fa014 100644
--- 
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/questions/ConnectToClusterQuestion.java
+++ 
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/questions/ConnectToClusterQuestion.java
@@ -86,6 +86,9 @@ public class ConnectToClusterQuestion {
      * Ask for connect to the cluster and suggest to save the last connected 
URL as default.
      */
     public void askQuestionOnReplStart() {
+        if (session.isConnectedToNode()) {
+            return;
+        }
         String defaultUrl = 
configManagerProvider.get().getCurrentProperty(ConfigConstants.CLUSTER_URL);
         String lastConnectedUrl = 
stateConfigProvider.get().getProperty(ConfigConstants.LAST_CONNECTED_URL);
         QuestionUiComponent question;
diff --git 
a/modules/cli/src/test/java/org/apache/ignite/internal/cli/commands/UrlOptionsNegativeTest.java
 
b/modules/cli/src/test/java/org/apache/ignite/internal/cli/commands/UrlOptionsNegativeTest.java
index 00511f4950..3bf8b67591 100644
--- 
a/modules/cli/src/test/java/org/apache/ignite/internal/cli/commands/UrlOptionsNegativeTest.java
+++ 
b/modules/cli/src/test/java/org/apache/ignite/internal/cli/commands/UrlOptionsNegativeTest.java
@@ -44,7 +44,7 @@ import 
org.apache.ignite.internal.cli.commands.cluster.topology.LogicalTopologyC
 import 
org.apache.ignite.internal.cli.commands.cluster.topology.LogicalTopologyReplCommand;
 import 
org.apache.ignite.internal.cli.commands.cluster.topology.PhysicalTopologyCommand;
 import 
org.apache.ignite.internal.cli.commands.cluster.topology.PhysicalTopologyReplCommand;
-import org.apache.ignite.internal.cli.commands.connect.ConnectCommand;
+import org.apache.ignite.internal.cli.commands.connect.ConnectReplCommand;
 import org.apache.ignite.internal.cli.commands.node.NodeNameOrUrl;
 import 
org.apache.ignite.internal.cli.commands.node.config.NodeConfigShowCommand;
 import 
org.apache.ignite.internal.cli.commands.node.config.NodeConfigShowReplCommand;
@@ -148,7 +148,7 @@ public class UrlOptionsNegativeTest {
                 arguments(LogicalTopologyReplCommand.class, 
CLUSTER_URL_OPTION, List.of()),
                 arguments(PhysicalTopologyReplCommand.class, 
CLUSTER_URL_OPTION, List.of()),
                 arguments(ClusterInitReplCommand.class, CLUSTER_URL_OPTION, 
List.of("--cluster-name=cluster", "--meta-storage-node=test")),
-                arguments(ConnectCommand.class, "", List.of())
+                arguments(ConnectReplCommand.class, "", List.of())
         // TODO https://issues.apache.org/jira/browse/IGNITE-17102
         //                Arguments.arguments(ClusterShowReplCommand.class, 
CLUSTER_URL_OPTION, List.of()),
         );
@@ -268,7 +268,7 @@ public class UrlOptionsNegativeTest {
     @Test
     void testConnectCommandWithoutParametersWithEmptyConfig() {
         configManagerProvider.configManager = new 
IniConfigManager(TestConfigManagerHelper.createEmptyConfig());
-        setUp(ConnectCommand.class);
+        setUp(ConnectReplCommand.class);
         cmd.execute();
 
         assertAll(

Reply via email to