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/05/12 14:40:23 UTC
[ignite-3] branch main updated: IGNITE-19244 Add file path completion to SSL config questions (#2069)
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 3252680632 IGNITE-19244 Add file path completion to SSL config questions (#2069)
3252680632 is described below
commit 3252680632b5c067a75c8a467dd8bd3c2ed4788b
Author: Vadim Pakhnushev <86...@users.noreply.github.com>
AuthorDate: Fri May 12 17:40:17 2023 +0300
IGNITE-19244 Add file path completion to SSL config questions (#2069)
---
.../questions/ItConnectToClusterTestBase.java | 14 +------
.../questions/ConnectToClusterQuestion.java | 20 ++++++---
.../flow/question/JlineQuestionWriterReader.java | 24 +++--------
.../question/JlineQuestionWriterReaderFactory.java | 47 ++++++++++++++++++++++
.../cli/core/flow/question/QuestionAsker.java | 36 ++++++++++++++---
.../core/flow/question/QuestionAskerFactory.java | 8 ++--
.../core/flow/question/QuestionWriterReader.java | 5 ++-
...eader.java => QuestionWriterReaderFactory.java} | 14 +++----
.../cli/core/repl/executor/ReplExecutor.java | 29 +++----------
.../internal/cli/commands/flow/FlowTest.java | 6 +--
10 files changed, 119 insertions(+), 84 deletions(-)
diff --git a/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/questions/ItConnectToClusterTestBase.java b/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/questions/ItConnectToClusterTestBase.java
index d9d3c3a62f..3ae37f3def 100644
--- a/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/questions/ItConnectToClusterTestBase.java
+++ b/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/questions/ItConnectToClusterTestBase.java
@@ -26,13 +26,9 @@ import java.nio.file.Path;
import org.apache.ignite.internal.cli.commands.CliCommandTestInitializedIntegrationBase;
import org.apache.ignite.internal.cli.commands.TopLevelCliReplCommand;
import org.apache.ignite.internal.cli.config.TestStateConfigProvider;
-import org.apache.ignite.internal.cli.core.flow.question.JlineQuestionWriterReader;
+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.prompt.PromptProvider;
-import org.jline.reader.LineReader;
-import org.jline.reader.LineReaderBuilder;
-import org.jline.reader.Parser;
-import org.jline.reader.impl.DefaultParser;
import org.jline.terminal.Terminal;
import org.jline.terminal.impl.DumbTerminal;
import org.junit.jupiter.api.AfterEach;
@@ -65,13 +61,7 @@ class ItConnectToClusterTestBase extends CliCommandTestInitializedIntegrationBas
input = Files.createTempFile(WORK_DIR, "input", "");
terminal = new DumbTerminal(Files.newInputStream(input), new FileOutputStream(FileDescriptor.out));
- Parser parser = new DefaultParser().escapeChars(null);
-
- LineReader reader = LineReaderBuilder.builder()
- .terminal(terminal)
- .parser(parser)
- .build();
- QuestionAskerFactory.setReadWriter(new JlineQuestionWriterReader(reader));
+ QuestionAskerFactory.setWriterReaderFactory(new JlineQuestionWriterReaderFactory(terminal));
}
@AfterEach
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 d2ee01e19f..8f2c02ce79 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
@@ -168,17 +168,25 @@ public class ConnectToClusterQuestion {
return Flows.<Void, SslConfig>acceptQuestion(question, () -> {
SslConfig config = new SslConfig();
- config.trustStorePath(escapeWindowsPath(enterString("trust store path")));
- config.trustStorePassword(enterString("trust store password"));
+ config.trustStorePath(escapeWindowsPath(enterFilePath("trust store path")));
+ config.trustStorePassword(enterPassword("trust store password"));
return config;
}).then(Flows.acceptQuestionFlow(question2, config -> {
- config.keyStorePath(escapeWindowsPath(enterString("key store path")));
- config.keyStorePassword(enterString("key store password"));
+ config.keyStorePath(escapeWindowsPath(enterFilePath("key store path")));
+ config.keyStorePassword(enterPassword("key store password"));
}));
}
- private static String enterString(String question) {
- return QuestionAskerFactory.newQuestionAsker().askQuestion("Enter " + question + ": ");
+ private static String enterFilePath(String question) {
+ return QuestionAskerFactory.newQuestionAsker()
+ .completeFilePaths(true)
+ .askQuestion("Enter " + question + ": ");
+ }
+
+ private static String enterPassword(String question) {
+ return QuestionAskerFactory.newQuestionAsker()
+ .maskInput(true)
+ .askQuestion("Enter " + question + ": ");
}
/** Escapes single backslashes to double backslashes, skips double backslashes if they are present. */
diff --git a/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/flow/question/JlineQuestionWriterReader.java b/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/flow/question/JlineQuestionWriterReader.java
index da6340f0e7..3ebd96fa53 100644
--- a/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/flow/question/JlineQuestionWriterReader.java
+++ b/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/flow/question/JlineQuestionWriterReader.java
@@ -17,43 +17,29 @@
package org.apache.ignite.internal.cli.core.flow.question;
-import java.util.function.Consumer;
import org.apache.ignite.internal.cli.core.flow.FlowInterruptException;
import org.jline.reader.EndOfFileException;
import org.jline.reader.LineReader;
import org.jline.reader.MaskingCallback;
import org.jline.reader.UserInterruptException;
+import org.jline.reader.impl.SimpleMaskingCallback;
/**
* Implementation of {@link QuestionWriterReader} based on {@link LineReader}.
*/
public class JlineQuestionWriterReader implements QuestionWriterReader {
private final LineReader reader;
- private final Consumer<Boolean> widgetsEnabler;
-
- public JlineQuestionWriterReader(LineReader reader, Consumer<Boolean> widgetsEnabler) {
- this.reader = reader;
- this.widgetsEnabler = widgetsEnabler;
- }
public JlineQuestionWriterReader(LineReader reader) {
- this(reader, enable -> {});
+ this.reader = reader;
}
/** {@inheritDoc} */
@Override
- public String readAnswer(String question) {
- widgetsEnabler.accept(false);
- reader.setVariable(LineReader.DISABLE_HISTORY, true);
- String s = readLine(question);
- reader.setVariable(LineReader.DISABLE_HISTORY, false);
- widgetsEnabler.accept(true);
- return s;
- }
-
- private String readLine(String question) {
+ public String readAnswer(String question, boolean maskInput) {
try {
- return reader.readLine(question, null, (MaskingCallback) null, null);
+ MaskingCallback callback = maskInput ? new SimpleMaskingCallback('*') : null;
+ return reader.readLine(question, null, callback, null);
} catch (UserInterruptException /* Ctrl-C pressed */ | EndOfFileException /* Ctrl-D pressed */ ignored) {
throw new FlowInterruptException();
}
diff --git a/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/flow/question/JlineQuestionWriterReaderFactory.java b/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/flow/question/JlineQuestionWriterReaderFactory.java
new file mode 100644
index 0000000000..6b3baa615d
--- /dev/null
+++ b/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/flow/question/JlineQuestionWriterReaderFactory.java
@@ -0,0 +1,47 @@
+/*
+ * 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.core.flow.question;
+
+import org.jline.builtins.Completers.FileNameCompleter;
+import org.jline.reader.LineReader;
+import org.jline.reader.LineReaderBuilder;
+import org.jline.reader.Parser;
+import org.jline.reader.impl.DefaultParser;
+import org.jline.terminal.Terminal;
+
+/** Creates {@link QuestionWriterReader} using custom {@link LineReader}. **/
+public class JlineQuestionWriterReaderFactory implements QuestionWriterReaderFactory {
+ private final Terminal terminal;
+
+ public JlineQuestionWriterReaderFactory(Terminal terminal) {
+ this.terminal = terminal;
+ }
+
+ @Override
+ public QuestionWriterReader createWriterReader(boolean completeFilePaths) {
+ Parser parser = new DefaultParser().escapeChars(null);
+ LineReaderBuilder builder = LineReaderBuilder.builder()
+ .terminal(terminal)
+ .parser(parser);
+ if (completeFilePaths) {
+ builder.completer(new FileNameCompleter());
+ }
+ LineReader reader = builder.build();
+ return new JlineQuestionWriterReader(reader);
+ }
+}
diff --git a/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/flow/question/QuestionAsker.java b/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/flow/question/QuestionAsker.java
index ec64c573d4..f817d5bd96 100644
--- a/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/flow/question/QuestionAsker.java
+++ b/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/flow/question/QuestionAsker.java
@@ -24,10 +24,14 @@ import java.util.List;
*/
public class QuestionAsker {
- private final QuestionWriterReader readWriter;
+ private final QuestionWriterReaderFactory writerReaderFactory;
- public QuestionAsker(QuestionWriterReader readWriter) {
- this.readWriter = readWriter;
+ private boolean completeFilePaths;
+
+ private boolean maskInput;
+
+ public QuestionAsker(QuestionWriterReaderFactory writerReaderFactory) {
+ this.writerReaderFactory = writerReaderFactory;
}
/**
@@ -40,7 +44,7 @@ public class QuestionAsker {
* @return value of answer.
*/
public <I, O> O askQuestion(String question, I input, List<QuestionAnswer<I, O>> answers) {
- String userAnswer = readWriter.readAnswer(question);
+ String userAnswer = askQuestion(question);
for (QuestionAnswer<I, O> answer : answers) {
if (answer.isAnswer(userAnswer)) {
@@ -57,6 +61,28 @@ public class QuestionAsker {
* @return value of answer.
*/
public String askQuestion(String question) {
- return readWriter.readAnswer(question);
+ QuestionWriterReader readWriter = writerReaderFactory.createWriterReader(completeFilePaths);
+ return readWriter.readAnswer(question, maskInput);
+ }
+
+ /**
+ * Enables file paths completion.
+ *
+ * @param completeFilePaths If {@code true}, file paths will be completed.
+ */
+ public QuestionAsker completeFilePaths(boolean completeFilePaths) {
+ this.completeFilePaths = completeFilePaths;
+ return this;
}
+
+ /**
+ * Enables input masking.
+ *
+ * @param maskInput If {@code true}, user input will be masked with asterisks.
+ */
+ public QuestionAsker maskInput(boolean maskInput) {
+ this.maskInput = maskInput;
+ return this;
+ }
+
}
diff --git a/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/flow/question/QuestionAskerFactory.java b/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/flow/question/QuestionAskerFactory.java
index 81337f9464..fba82e578c 100644
--- a/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/flow/question/QuestionAskerFactory.java
+++ b/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/flow/question/QuestionAskerFactory.java
@@ -21,13 +21,13 @@ package org.apache.ignite.internal.cli.core.flow.question;
* Factory of {@link QuestionAsker}.
*/
public class QuestionAskerFactory {
- private static volatile QuestionWriterReader questionWriterReader;
+ private static volatile QuestionWriterReaderFactory writerReaderFactory;
public static QuestionAsker newQuestionAsker() {
- return new QuestionAsker(questionWriterReader);
+ return new QuestionAsker(writerReaderFactory);
}
- public static void setReadWriter(QuestionWriterReader questionWriterReader) {
- QuestionAskerFactory.questionWriterReader = questionWriterReader;
+ public static void setWriterReaderFactory(QuestionWriterReaderFactory writerReaderFactory) {
+ QuestionAskerFactory.writerReaderFactory = writerReaderFactory;
}
}
diff --git a/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/flow/question/QuestionWriterReader.java b/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/flow/question/QuestionWriterReader.java
index 6ce79776db..9dc37fa7c8 100644
--- a/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/flow/question/QuestionWriterReader.java
+++ b/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/flow/question/QuestionWriterReader.java
@@ -24,8 +24,9 @@ public interface QuestionWriterReader {
/**
* Write question to output and read answer from input.
*
- * @param question question to ask.
+ * @param question Question to ask.
+ * @param maskInput If {@code true}, user input will be masked with asterisks.
* @return user answer.
*/
- String readAnswer(String question);
+ String readAnswer(String question, boolean maskInput);
}
diff --git a/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/flow/question/QuestionWriterReader.java b/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/flow/question/QuestionWriterReaderFactory.java
similarity index 70%
copy from modules/cli/src/main/java/org/apache/ignite/internal/cli/core/flow/question/QuestionWriterReader.java
copy to modules/cli/src/main/java/org/apache/ignite/internal/cli/core/flow/question/QuestionWriterReaderFactory.java
index 6ce79776db..0198102ac1 100644
--- a/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/flow/question/QuestionWriterReader.java
+++ b/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/flow/question/QuestionWriterReaderFactory.java
@@ -17,15 +17,13 @@
package org.apache.ignite.internal.cli.core.flow.question;
-/**
- * Question writer and reader interface.
- */
-public interface QuestionWriterReader {
+/** Factory for creating instances of {@link QuestionWriterReader}. */
+public interface QuestionWriterReaderFactory {
/**
- * Write question to output and read answer from input.
+ * Creates an instance of {@link QuestionWriterReader}.
*
- * @param question question to ask.
- * @return user answer.
+ * @param completeFilePaths If {@code true}, this instance will complete input as file paths.
+ * @return Question reader.
*/
- String readAnswer(String question);
+ QuestionWriterReader createWriterReader(boolean completeFilePaths);
}
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 574eeedeb5..945c801f07 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
@@ -21,7 +21,6 @@ import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.function.Consumer;
import java.util.function.Supplier;
import org.apache.ignite.internal.cli.commands.node.NodeNameOrUrl;
import org.apache.ignite.internal.cli.config.StateFolderProvider;
@@ -29,7 +28,7 @@ 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.JlineQuestionWriterReader;
+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;
@@ -88,7 +87,7 @@ public class ReplExecutor {
this.nodeNameRegistry = nodeNameRegistry;
}
- private static TailTipWidgets createTailTipWidgets(SystemRegistryImpl registry, LineReader reader) {
+ private static void createTailTipWidgets(SystemRegistryImpl registry, LineReader reader) {
TailTipWidgets widgets = new TailTipWidgets(reader, registry::commandDescription, 5,
TailTipWidgets.TipType.COMPLETER);
widgets.enable();
@@ -101,7 +100,6 @@ public class ReplExecutor {
});
// Workaround for jline issue where TailTipWidgets will produce NPE when passed a bracket
registry.setScriptDescription(cmdLine -> null);
- return widgets;
}
/**
@@ -152,32 +150,15 @@ public class ReplExecutor {
}
}
- private static void setupWidgets(Repl repl, SystemRegistryImpl registry, LineReader reader) {
- Consumer<Boolean> widgetsEnabler;
+ private void setupWidgets(Repl repl, SystemRegistryImpl registry, LineReader reader) {
if (repl.isTailTipWidgetsEnabled()) {
- TailTipWidgets widgets = createTailTipWidgets(registry, reader);
- widgetsEnabler = enable -> {
- if (enable) {
- widgets.enable();
- } else {
- widgets.disable();
- }
- };
+ createTailTipWidgets(registry, reader);
} else if (repl.isAutosuggestionsWidgetsEnabled()) {
AutosuggestionWidgets widgets = new AutosuggestionWidgets(reader);
widgets.enable();
- widgetsEnabler = enable -> {
- if (enable) {
- widgets.enable();
- } else {
- widgets.disable();
- }
- };
- } else {
- widgetsEnabler = enable -> {};
}
- QuestionAskerFactory.setReadWriter(new JlineQuestionWriterReader(reader, widgetsEnabler));
+ QuestionAskerFactory.setWriterReaderFactory(new JlineQuestionWriterReaderFactory(terminal));
}
private LineReader createReader(Completer completer) {
diff --git a/modules/cli/src/test/java/org/apache/ignite/internal/cli/commands/flow/FlowTest.java b/modules/cli/src/test/java/org/apache/ignite/internal/cli/commands/flow/FlowTest.java
index 700330e890..d72613a933 100644
--- a/modules/cli/src/test/java/org/apache/ignite/internal/cli/commands/flow/FlowTest.java
+++ b/modules/cli/src/test/java/org/apache/ignite/internal/cli/commands/flow/FlowTest.java
@@ -38,11 +38,10 @@ import org.apache.ignite.internal.cli.core.flow.Flow;
import org.apache.ignite.internal.cli.core.flow.Flowable;
import org.apache.ignite.internal.cli.core.flow.builder.FlowBuilder;
import org.apache.ignite.internal.cli.core.flow.builder.Flows;
-import org.apache.ignite.internal.cli.core.flow.question.JlineQuestionWriterReader;
+import org.apache.ignite.internal.cli.core.flow.question.JlineQuestionWriterReaderFactory;
import org.apache.ignite.internal.cli.core.flow.question.QuestionAnswer;
import org.apache.ignite.internal.cli.core.flow.question.QuestionAskerFactory;
import org.apache.ignite.internal.cli.core.repl.context.CommandLineContextProvider;
-import org.jline.reader.impl.LineReaderImpl;
import org.jline.terminal.Terminal;
import org.jline.terminal.impl.DumbTerminal;
import org.junit.jupiter.api.AfterEach;
@@ -100,8 +99,7 @@ class FlowTest {
input = Files.createTempFile("input", "");
input.toFile().deleteOnExit();
terminal = new DumbTerminal(Files.newInputStream(input), new FileOutputStream(FileDescriptor.out));
- LineReaderImpl reader = new LineReaderImpl(terminal);
- QuestionAskerFactory.setReadWriter(new JlineQuestionWriterReader(reader));
+ QuestionAskerFactory.setWriterReaderFactory(new JlineQuestionWriterReaderFactory(terminal));
out = new StringWriter();
errOut = new StringWriter();
CommandLineContextProvider.setWriters(new PrintWriter(out), new PrintWriter(errOut));