This is an automated email from the ASF dual-hosted git repository. tanxinyu pushed a commit to branch master_performance in repository https://gitbox.apache.org/repos/asf/iotdb.git
commit 89d5c48e9978d38463579d462a5be9e8f2e8b869 Author: Zhong Wang <[email protected]> AuthorDate: Thu Nov 25 22:58:15 2021 +0800 [IOTDB-1673] CLI refactor and upgrade to JLine3 (#4458) * [IOTDB-1673] CLI refactor 1. Upgrade to Jline3. 2. Remove the CLI implmentation for Windows since Jline3 is platform independent. 3. Support persisted command history. 4. Support multi-line edition. 5. Exit by pressing CTRL+D or CTRL+C twice. 6. Add auto pair and auto suggestion widgets. 7. Add keyword highlighter and completer. * Resolve comment 1. Update LICENSE-binary --- LICENSE-binary | 6 +- .../org/apache/iotdb/db/qp/sql/IoTDBSqlLexer.g4 | 4 +- cli/pom.xml | 11 +- cli/src/assembly/resources/sbin/start-cli.bat | 2 +- cli/src/main/java/org/apache/iotdb/cli/Cli.java | 40 +++-- .../apache/iotdb/cli/IoTDBSyntaxHighlighter.java | 76 +++++++++ cli/src/main/java/org/apache/iotdb/cli/WinCli.java | 175 --------------------- .../org/apache/iotdb/cli/utils/JlineUtils.java | 107 +++++++++++++ .../org/apache/iotdb/tool/AbstractCsvTool.java | 3 +- .../main/java/org/apache/iotdb/tool/ExportCsv.java | 19 ++- pom.xml | 6 +- 11 files changed, 240 insertions(+), 209 deletions(-) diff --git a/LICENSE-binary b/LICENSE-binary index ce5c2aa..de449d9 100644 --- a/LICENSE-binary +++ b/LICENSE-binary @@ -271,16 +271,12 @@ org.xerial.snappy:snappy-java:1.1.8.4 io.airlift.airline:0.8 net.minidev:accessors-smart:1.2 -BSD 2-Clause ------------- -jline:jline:2.14.5 - BSD 3-Clause ------------ org.antlr:antlr-runtime:4.8-1 org.ow2.asm:asm:5.0.4 -org.jline:jline:3.10.0 +org.jline:jline:3.21.0 MIT License diff --git a/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlLexer.g4 b/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlLexer.g4 index fdcd67f..be310fb 100644 --- a/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlLexer.g4 +++ b/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlLexer.g4 @@ -23,9 +23,11 @@ lexer grammar IoTDBSqlLexer; * 1. Whitespace */ +// Instead of discarding whitespace completely, send them to a channel invisable to the parser, so +// that the lexer could still produce WS tokens for the CLI's highlighter. WS : - [ \u000B\t\r\n]+ -> skip + [ \u000B\t\r\n]+ -> channel(HIDDEN) ; diff --git a/cli/pom.xml b/cli/pom.xml index 9bcb861..741ff6d 100644 --- a/cli/pom.xml +++ b/cli/pom.xml @@ -66,10 +66,19 @@ <version>0.9.2</version> </dependency> <dependency> - <groupId>jline</groupId> + <groupId>org.jline</groupId> <artifactId>jline</artifactId> </dependency> <dependency> + <groupId>net.java.dev.jna</groupId> + <artifactId>jna</artifactId> + </dependency> + <dependency> + <groupId>org.apache.iotdb</groupId> + <artifactId>iotdb-antlr</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> <groupId>org.apache.iotdb</groupId> <artifactId>iotdb-server</artifactId> <version>${project.version}</version> diff --git a/cli/src/assembly/resources/sbin/start-cli.bat b/cli/src/assembly/resources/sbin/start-cli.bat index 99da3fd..3868786 100644 --- a/cli/src/assembly/resources/sbin/start-cli.bat +++ b/cli/src/assembly/resources/sbin/start-cli.bat @@ -28,7 +28,7 @@ pushd %~dp0.. if NOT DEFINED IOTDB_CLI_HOME set IOTDB_CLI_HOME=%CD% popd -if NOT DEFINED MAIN_CLASS set MAIN_CLASS=org.apache.iotdb.cli.WinCli +if NOT DEFINED MAIN_CLASS set MAIN_CLASS=org.apache.iotdb.cli.Cli if NOT DEFINED JAVA_HOME goto :err @REM ----------------------------------------------------------------------------- diff --git a/cli/src/main/java/org/apache/iotdb/cli/Cli.java b/cli/src/main/java/org/apache/iotdb/cli/Cli.java index 6e57d27..6d7675f 100644 --- a/cli/src/main/java/org/apache/iotdb/cli/Cli.java +++ b/cli/src/main/java/org/apache/iotdb/cli/Cli.java @@ -18,12 +18,12 @@ */ package org.apache.iotdb.cli; +import org.apache.iotdb.cli.utils.JlineUtils; import org.apache.iotdb.exception.ArgsErrorException; import org.apache.iotdb.jdbc.Config; import org.apache.iotdb.jdbc.IoTDBConnection; import org.apache.iotdb.rpc.RpcUtils; -import jline.console.ConsoleReader; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.DefaultParser; @@ -31,6 +31,9 @@ import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import org.apache.thrift.TException; +import org.jline.reader.EndOfFileException; +import org.jline.reader.LineReader; +import org.jline.reader.UserInterruptException; import java.io.IOException; import java.sql.DriverManager; @@ -42,6 +45,7 @@ import static org.apache.iotdb.cli.utils.IoTPrinter.println; public class Cli extends AbstractCli { private static CommandLine commandLine; + private static LineReader lineReader; /** * IoTDB Client main function. @@ -49,7 +53,7 @@ public class Cli extends AbstractCli { * @param args launch arguments * @throws ClassNotFoundException ClassNotFoundException */ - public static void main(String[] args) throws ClassNotFoundException { + public static void main(String[] args) throws ClassNotFoundException, IOException { Class.forName(Config.JDBC_DRIVER_NAME); Options options = createOptions(); HelpFormatter hf = new HelpFormatter(); @@ -72,6 +76,7 @@ public class Cli extends AbstractCli { return; } + lineReader = JlineUtils.getLineReader(); serve(); } @@ -129,13 +134,10 @@ public class Cli extends AbstractCli { println(IOTDB_CLI_PREFIX + "> can't execute sql because" + e.getMessage()); } } - try (ConsoleReader reader = new ConsoleReader()) { - reader.setExpandEvents(false); - if (password == null) { - password = reader.readLine("please input your password:", '\0'); - } - receiveCommands(reader); + if (password == null) { + password = lineReader.readLine("please input your password:", '\0'); } + receiveCommands(lineReader); } catch (ArgsErrorException e) { println(IOTDB_CLI_PREFIX + "> input params error because" + e.getMessage()); } catch (Exception e) { @@ -143,7 +145,7 @@ public class Cli extends AbstractCli { } } - private static void receiveCommands(ConsoleReader reader) throws TException, IOException { + private static void receiveCommands(LineReader reader) throws TException { try (IoTDBConnection connection = (IoTDBConnection) DriverManager.getConnection( @@ -157,10 +159,22 @@ public class Cli extends AbstractCli { displayLogo(properties.getVersion()); println(IOTDB_CLI_PREFIX + "> login successfully"); while (true) { - s = reader.readLine(IOTDB_CLI_PREFIX + "> ", null); - boolean continues = processCommand(s, connection); - if (!continues) { - break; + try { + s = reader.readLine(IOTDB_CLI_PREFIX + "> ", null); + boolean continues = processCommand(s, connection); + if (!continues) { + break; + } + } catch (UserInterruptException e) { + // Exit on signal INT requires confirmation. + try { + reader.readLine("Press CTRL+C again to exit, or press ENTER to continue", '\0'); + } catch (UserInterruptException | EndOfFileException e2) { + System.exit(0); + } + } catch (EndOfFileException e) { + // Exit on EOF (usually by pressing CTRL+D). + System.exit(0); } } } catch (SQLException e) { diff --git a/cli/src/main/java/org/apache/iotdb/cli/IoTDBSyntaxHighlighter.java b/cli/src/main/java/org/apache/iotdb/cli/IoTDBSyntaxHighlighter.java new file mode 100644 index 0000000..82e9866 --- /dev/null +++ b/cli/src/main/java/org/apache/iotdb/cli/IoTDBSyntaxHighlighter.java @@ -0,0 +1,76 @@ +/* + * 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.iotdb.cli; + +import org.apache.iotdb.cli.utils.JlineUtils; +import org.apache.iotdb.db.qp.sql.IoTDBSqlLexer; + +import org.antlr.v4.runtime.CharStream; +import org.antlr.v4.runtime.CharStreams; +import org.antlr.v4.runtime.Token; +import org.jline.reader.Highlighter; +import org.jline.reader.LineReader; +import org.jline.utils.AttributedString; +import org.jline.utils.AttributedStringBuilder; +import org.jline.utils.AttributedStyle; + +import java.util.regex.Pattern; + +import static org.jline.utils.AttributedStyle.DEFAULT; +import static org.jline.utils.AttributedStyle.GREEN; + +public class IoTDBSyntaxHighlighter implements Highlighter { + + private static final AttributedStyle KEYWORD_STYLE = DEFAULT.foreground(GREEN); + + @Override + public AttributedString highlight(LineReader reader, String buffer) { + CharStream stream = CharStreams.fromString(buffer); + IoTDBSqlLexer tokenSource = new IoTDBSqlLexer(stream); + tokenSource.removeErrorListeners(); + AttributedStringBuilder builder = new AttributedStringBuilder(); + while (true) { + Token token = tokenSource.nextToken(); + int type = token.getType(); + if (type == Token.EOF) { + break; + } + String text = token.getText(); + + if (isKeyword(text)) { + builder.styled(KEYWORD_STYLE, text); + } else { + builder.append(text); + } + } + + return builder.toAttributedString(); + } + + @Override + public void setErrorPattern(Pattern errorPattern) {} + + @Override + public void setErrorIndex(int errorIndex) {} + + private boolean isKeyword(String token) { + return JlineUtils.SQL_KEYWORDS.contains(token.toUpperCase()); + } +} diff --git a/cli/src/main/java/org/apache/iotdb/cli/WinCli.java b/cli/src/main/java/org/apache/iotdb/cli/WinCli.java deleted file mode 100644 index 7d9e938..0000000 --- a/cli/src/main/java/org/apache/iotdb/cli/WinCli.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * 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.iotdb.cli; - -import org.apache.iotdb.exception.ArgsErrorException; -import org.apache.iotdb.jdbc.Config; -import org.apache.iotdb.jdbc.IoTDBConnection; -import org.apache.iotdb.rpc.RpcUtils; - -import org.apache.commons.cli.CommandLine; -import org.apache.commons.cli.CommandLineParser; -import org.apache.commons.cli.DefaultParser; -import org.apache.commons.cli.HelpFormatter; -import org.apache.commons.cli.Options; -import org.apache.commons.cli.ParseException; -import org.apache.thrift.TException; - -import java.io.Console; -import java.sql.DriverManager; -import java.sql.SQLException; -import java.util.Scanner; - -import static org.apache.iotdb.cli.utils.IoTPrinter.print; -import static org.apache.iotdb.cli.utils.IoTPrinter.println; - -/** args[]: -h 127.0.0.1 -p 6667 -u root -pw root */ -public class WinCli extends AbstractCli { - - private static CommandLine commandLine; - - /** - * main function. - * - * @param args -console args - */ - public static void main(String[] args) throws ClassNotFoundException { - Class.forName(Config.JDBC_DRIVER_NAME); - Options options = createOptions(); - HelpFormatter hf = new HelpFormatter(); - hf.setWidth(MAX_HELP_CONSOLE_WIDTH); - commandLine = null; - - if (args == null || args.length == 0) { - println("Require more params input, please check the following hint."); - hf.printHelp(IOTDB_CLI_PREFIX, options, true); - return; - } - - init(); - String[] newArgs = removePasswordArgs(args); - String[] newArgs2 = processExecuteArgs(newArgs); - boolean continues = parseCommandLine(options, newArgs2, hf); - if (!continues) { - return; - } - - serve(); - } - - private static String readPassword() { - Console c = System.console(); - if (c == null) { // IN ECLIENTPSE IDE - print(IOTDB_CLI_PREFIX + "> please input password: "); - Scanner scanner = new Scanner(System.in); - return scanner.nextLine(); - } else { // Outside Eclipse IDE - return new String(c.readPassword(IOTDB_CLI_PREFIX + "> please input password: ")); - } - } - - private static boolean parseCommandLine(Options options, String[] newArgs, HelpFormatter hf) { - try { - CommandLineParser parser = new DefaultParser(); - commandLine = parser.parse(options, newArgs); - if (commandLine.hasOption(HELP_ARGS)) { - hf.printHelp(IOTDB_CLI_PREFIX, options, true); - return false; - } - if (commandLine.hasOption(RPC_COMPRESS_ARGS)) { - Config.rpcThriftCompressionEnable = true; - } - if (commandLine.hasOption(ISO8601_ARGS)) { - timeFormat = RpcUtils.setTimeFormat("long"); - } - if (commandLine.hasOption(MAX_PRINT_ROW_COUNT_ARGS)) { - setMaxDisplayNumber(commandLine.getOptionValue(MAX_PRINT_ROW_COUNT_ARGS)); - } - } catch (ParseException e) { - println("Require more params input, please check the following hint."); - hf.printHelp(IOTDB_CLI_PREFIX, options, true); - return false; - } catch (NumberFormatException e) { - println( - IOTDB_CLI_PREFIX - + "> error format of max print row count, it should be an integer number"); - return false; - } - return true; - } - - private static void serve() { - try (Scanner scanner = new Scanner(System.in)) { - host = checkRequiredArg(HOST_ARGS, HOST_NAME, commandLine, false, host); - port = checkRequiredArg(PORT_ARGS, PORT_NAME, commandLine, false, port); - username = checkRequiredArg(USERNAME_ARGS, USERNAME_NAME, commandLine, true, null); - password = commandLine.getOptionValue(PASSWORD_ARGS); - if (password == null) { - password = readPassword(); - } - if (hasExecuteSQL) { - try (IoTDBConnection connection = - (IoTDBConnection) - DriverManager.getConnection( - Config.IOTDB_URL_PREFIX + host + ":" + port + "/", username, password)) { - properties = connection.getServerProperties(); - timestampPrecision = properties.getTimestampPrecision(); - AGGREGRATE_TIME_LIST.addAll(properties.getSupportedTimeAggregationOperations()); - processCommand(execute, connection); - return; - } catch (SQLException e) { - println(IOTDB_CLI_PREFIX + "> can't execute sql because" + e.getMessage()); - } - } - - receiveCommands(scanner); - } catch (ArgsErrorException e) { - println(IOTDB_CLI_PREFIX + "> input params error because" + e.getMessage()); - } catch (Exception e) { - println(IOTDB_CLI_PREFIX + "> exit cli with error " + e.getMessage()); - } - } - - private static void receiveCommands(Scanner scanner) throws TException { - try (IoTDBConnection connection = - (IoTDBConnection) - DriverManager.getConnection( - Config.IOTDB_URL_PREFIX + host + ":" + port + "/", username, password)) { - properties = connection.getServerProperties(); - AGGREGRATE_TIME_LIST.addAll(properties.getSupportedTimeAggregationOperations()); - timestampPrecision = properties.getTimestampPrecision(); - - echoStarting(); - displayLogo(properties.getVersion()); - println(IOTDB_CLI_PREFIX + "> login successfully"); - while (true) { - print(IOTDB_CLI_PREFIX + "> "); - String s = scanner.nextLine(); - boolean continues = processCommand(s, connection); - if (!continues) { - break; - } - } - } catch (SQLException e) { - println( - String.format( - "%s> %s Host is %s, port is %s.", IOTDB_CLI_PREFIX, e.getMessage(), host, port)); - } - } -} diff --git a/cli/src/main/java/org/apache/iotdb/cli/utils/JlineUtils.java b/cli/src/main/java/org/apache/iotdb/cli/utils/JlineUtils.java new file mode 100644 index 0000000..e2f5c7d --- /dev/null +++ b/cli/src/main/java/org/apache/iotdb/cli/utils/JlineUtils.java @@ -0,0 +1,107 @@ +/* + * 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.iotdb.cli.utils; + +import org.apache.iotdb.cli.IoTDBSyntaxHighlighter; +import org.apache.iotdb.db.qp.sql.IoTDBSqlLexer; + +import org.jline.reader.LineReader; +import org.jline.reader.LineReader.Option; +import org.jline.reader.LineReaderBuilder; +import org.jline.reader.impl.DefaultParser.Bracket; +import org.jline.reader.impl.completer.StringsCompleter; +import org.jline.terminal.Size; +import org.jline.terminal.Terminal; +import org.jline.terminal.Terminal.Signal; +import org.jline.terminal.TerminalBuilder; +import org.jline.utils.OSUtils; +import org.jline.widget.AutopairWidgets; +import org.jline.widget.AutosuggestionWidgets; + +import java.io.File; +import java.io.IOException; +import java.util.Objects; +import java.util.Set; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +public class JlineUtils { + + public static final Pattern SQL_KEYWORD_PATTERN = Pattern.compile("([A-Z_]+)"); + public static final Set<String> SQL_KEYWORDS = + IntStream.range(0, IoTDBSqlLexer.VOCABULARY.getMaxTokenType()) + .mapToObj(IoTDBSqlLexer.VOCABULARY::getDisplayName) + .filter(Objects::nonNull) + .filter(w -> SQL_KEYWORD_PATTERN.matcher(w).matches()) + .collect(Collectors.toSet()); + + public static LineReader getLineReader() throws IOException { + Terminal terminal = TerminalBuilder.builder().build(); + if (terminal.getWidth() == 0 || terminal.getHeight() == 0) { + // Hard coded terminal size when redirecting. + terminal.setSize(new Size(120, 40)); + } + Thread executeThread = Thread.currentThread(); + // Register signal handler. Instead of shutting down the process, interrupt the current thread + // when signal INT is received (usually by pressing CTRL+C). + terminal.handle(Signal.INT, signal -> executeThread.interrupt()); + + LineReaderBuilder builder = LineReaderBuilder.builder(); + builder.terminal(terminal); + + // Handle the command history. By default, the number of commands will not exceed 500 and the + // size of the history fill will be less than 10 KB. See: + // org.jline.reader.impl.history#DefaultHistory + String historyFile = ".iotdb.history"; + String historyFilePath = System.getProperty("user.home") + File.separator + historyFile; + builder.variable(LineReader.HISTORY_FILE, new File(historyFilePath)); + + builder.highlighter(new IoTDBSyntaxHighlighter()); + + builder.completer(new StringsCompleter(SQL_KEYWORDS)); + + builder.option(Option.CASE_INSENSITIVE_SEARCH, true); + builder.option(Option.CASE_INSENSITIVE, true); + // See: https://www.gnu.org/software/bash/manual/html_node/Event-Designators.html + builder.option(Option.DISABLE_EVENT_EXPANSION, true); + + org.jline.reader.impl.DefaultParser parser = new org.jline.reader.impl.DefaultParser(); + // Make multi-line edition be triggered by unclosed brackets and unclosed quotes. + parser.setEofOnUnclosedBracket(Bracket.CURLY, Bracket.SQUARE, Bracket.ROUND); + parser.setEofOnUnclosedQuote(true); + builder.parser(parser); + LineReader lineReader = builder.build(); + if (OSUtils.IS_WINDOWS) { + // If enabled cursor remains in begin parenthesis (gitbash). + lineReader.setVariable(LineReader.BLINK_MATCHING_PAREN, 0); + } + + // Create auto-pair widgets + AutopairWidgets autopairWidgets = new AutopairWidgets(lineReader); + // Enable auto-pair + autopairWidgets.enable(); + // Create autosuggestion widgets + AutosuggestionWidgets autosuggestionWidgets = new AutosuggestionWidgets(lineReader); + // Enable autosuggestions + autosuggestionWidgets.enable(); + return lineReader; + } +} diff --git a/cli/src/main/java/org/apache/iotdb/tool/AbstractCsvTool.java b/cli/src/main/java/org/apache/iotdb/tool/AbstractCsvTool.java index f03275d..3294406 100644 --- a/cli/src/main/java/org/apache/iotdb/tool/AbstractCsvTool.java +++ b/cli/src/main/java/org/apache/iotdb/tool/AbstractCsvTool.java @@ -23,7 +23,6 @@ import org.apache.iotdb.rpc.IoTDBConnectionException; import org.apache.iotdb.rpc.StatementExecutionException; import org.apache.iotdb.session.Session; -import jline.internal.Nullable; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.Option; import org.apache.commons.cli.Options; @@ -210,7 +209,7 @@ public abstract class AbstractCsvTool { * @param filePath the directory to save the file */ public static Boolean writeCsvFile( - @Nullable List<String> headerNames, List<List<Object>> records, String filePath) { + List<String> headerNames, List<List<Object>> records, String filePath) { try { CSVPrinter printer = CSVFormat.DEFAULT diff --git a/cli/src/main/java/org/apache/iotdb/tool/ExportCsv.java b/cli/src/main/java/org/apache/iotdb/tool/ExportCsv.java index 3450121..6d77a36 100644 --- a/cli/src/main/java/org/apache/iotdb/tool/ExportCsv.java +++ b/cli/src/main/java/org/apache/iotdb/tool/ExportCsv.java @@ -19,6 +19,7 @@ package org.apache.iotdb.tool; +import org.apache.iotdb.cli.utils.JlineUtils; import org.apache.iotdb.exception.ArgsErrorException; import org.apache.iotdb.rpc.IoTDBConnectionException; import org.apache.iotdb.rpc.RpcUtils; @@ -28,7 +29,6 @@ import org.apache.iotdb.session.SessionDataSet; import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType; import org.apache.iotdb.tsfile.read.common.RowRecord; -import jline.console.ConsoleReader; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.DefaultParser; @@ -39,8 +39,13 @@ import org.apache.commons.cli.ParseException; import org.apache.commons.csv.CSVFormat; import org.apache.commons.csv.CSVPrinter; import org.apache.commons.csv.QuoteMode; +import org.jline.reader.LineReader; -import java.io.*; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.io.PrintWriter; import java.time.Instant; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; @@ -83,7 +88,7 @@ public class ExportCsv extends AbstractCsvTool { private static final int EXPORT_PER_LINE_COUNT = 10000; /** main function of export csv tool. */ - public static void main(String[] args) throws IOException { + public static void main(String[] args) { Options options = createOptions(); HelpFormatter hf = new HelpFormatter(); CommandLine commandLine; @@ -124,15 +129,13 @@ public class ExportCsv extends AbstractCsvTool { String sql; if (sqlFile == null) { - ConsoleReader reader = new ConsoleReader(); - reader.setExpandEvents(false); - sql = reader.readLine(TSFILEDB_CLI_PREFIX + "> please input query: "); + LineReader lineReader = JlineUtils.getLineReader(); + sql = lineReader.readLine(TSFILEDB_CLI_PREFIX + "> please input query: "); System.out.println(sql); String[] values = sql.trim().split(";"); for (int i = 0; i < values.length; i++) { dumpResult(values[i], i); } - reader.close(); } else { dumpFromSqlFile(sqlFile); } @@ -335,7 +338,7 @@ public class ExportCsv extends AbstractCsvTool { } } } else { - names.forEach(name -> headers.add(name)); + headers.addAll(names); } printer.printRecord(headers); diff --git a/pom.xml b/pom.xml index 6286eef..37f2f27 100644 --- a/pom.xml +++ b/pom.xml @@ -137,7 +137,7 @@ <common.pool2.version>2.11.1</common.pool2.version> <org.slf4j.version>1.7.32</org.slf4j.version> <guava.version>24.1.1</guava.version> - <jline.version>2.14.6</jline.version> + <jline.version>3.21.0</jline.version> <jetty.version>9.4.35.v20201120</jetty.version> <metrics.version>4.2.4</metrics.version> <javax.xml.bind.version>2.4.0-b180830.0359</javax.xml.bind.version> @@ -269,7 +269,7 @@ <version>${javax.xml.bind.version}</version> </dependency> <dependency> - <groupId>jline</groupId> + <groupId>org.jline</groupId> <artifactId>jline</artifactId> <version>${jline.version}</version> </dependency> @@ -508,7 +508,7 @@ <artifactId>gson</artifactId> <version>${gson.version}</version> </dependency> - <!-- for test container --> + <!-- for cli and test container --> <dependency> <groupId>net.java.dev.jna</groupId> <artifactId>jna</artifactId>
