Skip to content

Commit a67affd

Browse files
authored
Issue 558 (#559)
### What problem were solved in this pull request? Issue Number: #558 Problem: As I mentioned in the issue, students cannot use the arrow keys to browse the command history in the current cli. The existing code seems to want to use `readline`(GNU Readline library), which may conflict with the existing license. So I used replxx to improve this function in the cli. ### What is changed and how it works? #### Key changes: - 3rd party dependency: replxx has been added as a git submodule - `CMakeLists.txt` in `observer` - related cpp source files #### Basic logic: 1. The `CliCommunicator `class utilizes a `replxx::Replxx` instance to manage the interaction. 2. Every 5s, history saved to `./.miniob.history`. ### Other information 1. This PR focuses **solely** on the `observer -P cli` functionality. The **obclient** is **NOT** modified. 2. Default max_history_size = 1000. 3. Default config: when `current_time - previous_history_save_time > 5`, history_save.
1 parent 1446753 commit a67affd

File tree

18 files changed

+228
-287
lines changed

18 files changed

+228
-287
lines changed

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,6 @@
1010
[submodule "deps/3rd/benchmark"]
1111
path = deps/3rd/benchmark
1212
url = https://github.com/google/benchmark
13+
[submodule "deps/3rd/replxx"]
14+
path = deps/3rd/replxx
15+
url = https://github.com/AmokHuginnsson/replxx

CMakeLists.txt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ OPTION(USE_SIMD "Use SIMD" OFF)
3434
OPTION(USE_MUSL_LIBC "Use musl libc" OFF)
3535
OPTION(WITH_CPPLINGS "Compile cpplings" ON)
3636

37-
3837
MESSAGE(STATUS "HOME dir: $ENV{HOME}")
3938
#SET(ENV{变量名} 值)
4039
IF(WIN32)
@@ -172,6 +171,11 @@ SET(CMAKE_C_FLAGS ${CMAKE_COMMON_FLAGS})
172171

173172
MESSAGE(STATUS "CMAKE_CXX_FLAGS is " ${CMAKE_CXX_FLAGS})
174173

174+
# Line Reading configs
175+
MESSAGE(STATUS "Using replxx for line reading")
176+
FIND_PACKAGE(Threads REQUIRED)
177+
FIND_PACKAGE(replxx REQUIRED)
178+
175179
# ADD_SUBDIRECTORY(src bin) bin 为目标目录, 可以省略
176180
# ADD_SUBDIRECTORY(deps)
177181
ADD_SUBDIRECTORY(src)
@@ -184,4 +188,3 @@ ENDIF(WITH_BENCHMARK)
184188
IF(WITH_UNIT_TESTS)
185189
ADD_SUBDIRECTORY(unittest)
186190
ENDIF(WITH_UNIT_TESTS)
187-

build.sh

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,15 @@ function do_init
108108
mkdir -p build && \
109109
cd build && \
110110
${CMAKE_COMMAND_THIRD_PARTY} -DJSONCPP_WITH_TESTS=OFF -DJSONCPP_WITH_POST_BUILD_UNITTEST=OFF .. && \
111-
${MAKE_COMMAND} && \
111+
${MAKE_COMMAND} -j4 && \
112+
${MAKE_COMMAND} install
113+
114+
# build replxx
115+
cd ${TOPDIR}/deps/3rd/replxx && \
116+
mkdir -p build && \
117+
cd build && \
118+
${CMAKE_COMMAND_THIRD_PARTY} .. -DCMAKE_BUILD_TYPE=Release -DREPLXX_BUILD_EXAMPLES=OFF -DREPLXX_BUILD_PACKAGE=OFF && \
119+
${MAKE_COMMAND} -j4 && \
112120
${MAKE_COMMAND} install
113121

114122
cd $current_dir

cmake/readline.cmake

Lines changed: 0 additions & 12 deletions
This file was deleted.

deps/3rd/replxx

Submodule replxx added at 1f149bf

docker/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ RUN apt-get update && apt-get install -y locales apt-utils && rm -rf /var/lib/ap
1919
# && apt-get update
2020

2121
RUN apt-get update \
22-
&& apt-get install -y build-essential gdb cmake git wget flex texinfo libreadline-dev diffutils bison \
22+
&& apt-get install -y build-essential gdb cmake git wget flex texinfo diffutils bison \
2323
&& apt-get install -y clang-format vim sudo
2424

2525
RUN apt-get install -y openssh-server

src/common/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ IF(USE_MUSL_LIBC)
1212
TARGET_LINK_LIBRARIES(common execinfo)
1313
ENDIF(USE_MUSL_LIBC)
1414

15+
TARGET_LINK_LIBRARIES(common replxx::replxx)
16+
MESSAGE(STATUS "common uses replxx")
17+
1518
# 编译静态库时,自动会把同名的动态库给删除, 因此需要临时设置一下
1619
SET_TARGET_PROPERTIES(common PROPERTIES CLEAN_DIRECT_OUTPUT 1)
1720

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/* Copyright (c) 2021 OceanBase and/or its affiliates. All rights reserved.
2+
miniob is licensed under Mulan PSL v2.
3+
You can use this software according to the terms and conditions of the Mulan PSL v2.
4+
You may obtain a copy of Mulan PSL v2 at:
5+
http://license.coscl.org.cn/MulanPSL2
6+
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
7+
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
8+
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
9+
See the Mulan PSL v2 for more details. */
10+
11+
//
12+
// Created by Willaaaaaaa in 2025
13+
//
14+
15+
#include "common/linereader/line_reader.h"
16+
#include "common/lang/string.h"
17+
18+
namespace common {
19+
MiniobLineReader::MiniobLineReader() : history_file_(""), previous_history_save_time_(0), history_save_interval_(5) {}
20+
21+
MiniobLineReader::~MiniobLineReader() { reader_.history_save(history_file_); }
22+
23+
MiniobLineReader &MiniobLineReader::instance()
24+
{
25+
static MiniobLineReader instance;
26+
return instance;
27+
}
28+
29+
void MiniobLineReader::init(const std::string &history_file)
30+
{
31+
history_file_ = history_file;
32+
reader_.history_load(history_file_);
33+
}
34+
35+
std::string MiniobLineReader::my_readline(const std::string &prompt)
36+
{
37+
const char *cinput = nullptr;
38+
cinput = reader_.input(prompt);
39+
if (cinput == nullptr) {
40+
return "";
41+
}
42+
43+
std::string line = cinput;
44+
cinput = nullptr;
45+
46+
if (line.empty()) {
47+
return "";
48+
}
49+
50+
bool is_valid_input = false;
51+
for (auto c : line) {
52+
if (!isspace(c)) {
53+
is_valid_input = true;
54+
break;
55+
}
56+
}
57+
58+
if (is_valid_input) {
59+
reader_.history_add(line);
60+
check_and_save_history();
61+
}
62+
63+
return line;
64+
}
65+
66+
bool MiniobLineReader::is_exit_command(const std::string &cmd)
67+
{
68+
std::string lower_cmd = cmd;
69+
common::str_to_lower(lower_cmd);
70+
71+
bool is_exit = lower_cmd.compare(0, 4, "exit") == 0 || lower_cmd.compare(0, 3, "bye") == 0 ||
72+
lower_cmd.compare(0, 2, "\\q") == 0 || lower_cmd.compare(0, 11, "interrupted") == 0;
73+
74+
return is_exit;
75+
}
76+
77+
bool MiniobLineReader::check_and_save_history()
78+
{
79+
time_t current_time = time(nullptr);
80+
if (current_time - previous_history_save_time_ > history_save_interval_) {
81+
reader_.history_save(history_file_);
82+
previous_history_save_time_ = current_time;
83+
return true;
84+
}
85+
return false;
86+
}
87+
} // namespace common
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/* Copyright (c) 2021 OceanBase and/or its affiliates. All rights reserved.
2+
miniob is licensed under Mulan PSL v2.
3+
You can use this software according to the terms and conditions of the Mulan PSL v2.
4+
You may obtain a copy of Mulan PSL v2 at:
5+
http://license.coscl.org.cn/MulanPSL2
6+
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
7+
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
8+
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
9+
See the Mulan PSL v2 for more details. */
10+
11+
//
12+
// Created by Willaaaaaaa in 2025
13+
//
14+
15+
#ifndef COMMON_LINE_READER_H
16+
#define COMMON_LINE_READER_H
17+
18+
#include "replxx.hxx"
19+
20+
namespace common {
21+
/**
22+
* @brief A singleton class for line-reading, providing an interface to replxx。
23+
*/
24+
class MiniobLineReader
25+
{
26+
// The following private methods guarantee it's Singleton pattern
27+
private:
28+
MiniobLineReader();
29+
~MiniobLineReader();
30+
MiniobLineReader(const MiniobLineReader &) = delete;
31+
MiniobLineReader &operator=(const MiniobLineReader &) = delete;
32+
33+
public:
34+
/**
35+
* @brief Get the singleton instance
36+
* @return Reference to the singleton instance
37+
*/
38+
static MiniobLineReader &instance();
39+
40+
/**
41+
* @brief Initialize the lineReader with history file
42+
* @param history_file path/to/file
43+
*/
44+
void init(const std::string &history_file);
45+
46+
/**
47+
* @brief Read a line from input
48+
* @param prompt The prompt to display
49+
* @return input string
50+
*/
51+
std::string my_readline(const std::string &prompt);
52+
53+
/**
54+
* @brief Check if the command is an exit command
55+
* @param cmd The input command
56+
* @return True if the command is an exit command
57+
*/
58+
bool is_exit_command(const std::string &cmd);
59+
60+
private:
61+
/**
62+
* @brief Check if history should be auto-saved
63+
* @return True if history should be saved due to time interval
64+
*/
65+
bool check_and_save_history();
66+
67+
private:
68+
replxx::Replxx reader_;
69+
std::string history_file_;
70+
time_t previous_history_save_time_;
71+
int history_save_interval_;
72+
};
73+
} // namespace common
74+
75+
#endif // COMMON_LINE_READER_H

src/obclient/CMakeLists.txt

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,6 @@
11
ADD_EXECUTABLE(obclient)
22
MESSAGE("Begin to build " obclient)
33

4-
INCLUDE(readline)
5-
MINIOB_FIND_READLINE()
6-
7-
IF (HAVE_READLINE)
8-
TARGET_LINK_LIBRARIES(obclient ${READLINE_LIBRARY})
9-
TARGET_INCLUDE_DIRECTORIES(obclient PRIVATE ${READLINE_INCLUDE_DIR})
10-
ADD_DEFINITIONS(-DUSE_READLINE)
11-
MESSAGE ("obclient use readline")
12-
ELSE ()
13-
MESSAGE ("readline is not found")
14-
ENDIF()
15-
164
FILE(GLOB_RECURSE ALL_SRC *.cpp)
175
FOREACH (F ${ALL_SRC})
186

0 commit comments

Comments
 (0)